C#, C♯, C#相談室 Part96

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん (ワッチョイ 7633-kUv4)
垢版 |
2021/12/20(月) 11:03:25.88ID:sdn/+VfW0
!extend:checked:vvvvv:1000:512
!extend:checked:vvvvv:1000:512

■Visual Studio 2017 Community(無償の統合開発環境)等はこちら
http://www.visualstudio.com/downloads/

■コードを貼る場合はこちら
http://ideone.com/

■前スレ
C#, C♯, C#相談室 Part94
https://mevius.5ch.net/test/read.cgi/tech/1553075856/

■次スレは>>970が建てる事。
建てられない場合は他を指定する事。
VIPQ2_EXTDAT: checked:vvvvv:1000:512:: EXT was configured
44デフォルトの名無しさん (アウアウウー Sa9b-PN0l)
垢版 |
2022/02/05(土) 16:47:04.66ID:tJRnKD74a
構造体の配列のメモリ確保で
データを入れる事は
できますか
A[] ={{1,2,2},{3,4,2},{1,5,6}}
みたいなノリの

お願いいたします
45デフォルトの名無しさん (アウアウウー Sa9b-PN0l)
垢版 |
2022/02/05(土) 16:51:55.17ID:gB/WrKWla
それと多重配列で
初期値データ入れたり
2022/02/05(土) 17:50:07.67ID:B70fTfWxa
A = new int[][] { new int[] { 1, 2, 2 }, new int[] { 3, 4, 2 }, new int[] { 1, 5, 6 } };
47デフォルトの名無しさん (アウアウウー Sa9b-PN0l)
垢版 |
2022/02/06(日) 06:30:33.16ID:SLNZfJCCa
それと多重配列で
初期値データ入れたり
2022/02/06(日) 11:36:56.19ID:PShjp8Rsa
多重配列がどんなか知らないけどできるだろ。ぐぐれ
2022/02/06(日) 15:12:56.93ID:OIlcPbSe0
多重配列とか勝手に用語作って質問するのは良くないよ。
2022/02/06(日) 15:21:21.57ID:+LnLbHsI0
コマンドプロンプトで起動するソフトで
コマンドプロンプトだと途中処理取得できるけど

C#上でリアルタイムで途中処理表示させるのって
スレッドを非同期にするやりかたとか考えた方がいいの?
2022/02/06(日) 15:24:24.54ID:PShjp8Rsa
プロセスの標準出力を読むだけ
C#側がシングルスレッドでもリアルタイムに取得して表示できる
2022/02/06(日) 17:31:20.88ID:TTEcICQ70
>>49
グーグル先生は賢い「多重配列」で検索すると「多次元配列」が出てくる。間違える人が一定数居るんだな。
c#だと多次元配列じゃなくてコレクションを使うほうが多いが。
2022/02/06(日) 17:34:23.14ID:TTEcICQ70
>>50
非同期にしなくても表示出来るが非同期の方がスマート
2022/02/06(日) 20:51:37.74ID:St9v7rC+0
C#で多次元配列とか速度も遅いし普通は使わん
2022/02/07(月) 00:06:03.73ID:tbXg2wz+0
せやな
2022/02/07(月) 08:00:35.82ID:2lq/vobIM
コンソールを開きたまえ
2022/02/07(月) 15:46:58.65ID:zWOfGBGY0
C#を独学で勉強したいんですが何から手をつけたら良いでしょうか
言語はシェルやvbaはできます、Pythonもちょっとだけ
2022/02/07(月) 15:56:11.87ID:ZbbRMlPga
なんでc#やりたくなったのか思い出してそのやりたかったことをどうやったらできるかぐぐってやればいい
とりあえずvsインストールしてさっさと始めろ
考えたり人に聞くよりもまずは手動かせ
2022/02/07(月) 16:05:15.62ID:zWOfGBGY0
C#ってvisualstudioのインストールだけで出来るの?
PythonみたいにC#自体はインストール不要なん?
2022/02/07(月) 16:11:45.01ID:ZbbRMlPga
vsのインストーラー起動したらc#をインストールするかどうかチェックするところがある
とりあえずやってみりゃ分かる
2022/02/07(月) 16:17:47.79ID:zWOfGBGY0
なるほど、ありがとうございます
ちなみにやりたいと思った理由はなんとなくの思いつきです
2022/02/07(月) 17:33:25.04ID:CWmTnMKY0
最初に画面作る→コード作る
勝手にコード作るから書き換えるときリファクタリングでちゃんとなおさないと
ボタンとの連携が外れたりしてだるい
2022/02/11(金) 20:18:35.80ID:Wnuvjl9G0
C#EntityFrameworkでテーブルの有無をチェックする方法ってありますか?
今はDbSet<Entity>のFirst()で例外が出たら、で仮チェックしてます
SQL文で書けば良いと言われればそれまでですが、それとは別にLINQや
DbSet<Entity>.Where(x => x.~ = Id);
みたいな方法でチェックする事はできるのでしょうか?
2022/02/11(金) 20:31:49.53ID:kVpyHF8c0
わいならSELECT文書くな
2022/02/11(金) 20:38:37.22ID:dtTIM78z0
Dictionary<string, Func<T, TRESULT>>
みたいな事をやりたいのですが
どう書くのが正解でしょうか?
2022/02/11(金) 20:57:51.73ID:vdb8lbDWa
適当な関数宣言をもったinterface作って、それ派生のclassで実装して
dictionary<string, interfacename>?
2022/02/11(金) 21:24:52.36ID:Wnuvjl9G0
適当だが書き方の話なら

どこかに書く
bool func(int n) { if (n <= 3) { return true; } else { return false; } }

var a = new Dictionary<string, Func<int, bool>>();

a.Add("test2", func);
bool b2_t1 = a["test2"](1);
bool b2_t3 = a["test2"](3);
bool b2_f5 = a["test2"](5);

ラムダ
a.Add("test1", x => { if (x == 1) { return true; } else { return false; } });
bool b_t1 = a["test1"](1);
bool b_f3 = a["test1"](3);
bool b_f5 = a["test1"](5);

Funcを加工するなら>>66のようにinterface、他オブジェクト型とか識別子渡して型チェックとか?
68デフォルトの名無しさん (ワッチョイ 1736-Jms/)
垢版 |
2022/02/11(金) 21:26:42.58ID:Wnuvjl9G0
>>64ありがとうございます
SELECT 〜 FROM 〜やOBJECT_IDのべた書きって事ですよね
それしかないんかな
2022/02/11(金) 22:10:25.35ID:dtTIM78z0
>>66,67
すみませんありがとうございます
Tが色々な型のFuncを登録したいのですがinterfaceの書き方がわかりません
2022/02/11(金) 22:17:26.15ID:w2aWSXHv0
そもそもなぜテーブルがないとかいう状態になるのか
その設計を見直したほうが良いんじゃね
2022/02/11(金) 22:20:58.05ID:kVpyHF8c0
あれだろ、ワークテーブルがもし存在したら消したりとか
年度でテーブルを分けたいとかわけわからんこと言われたりとか
そういう用途だろ
2022/02/11(金) 22:26:34.03ID:vdb8lbDWa
>>69
実際どんなのが欲しいのか知らないけどこんな感じでいいんじゃないの?
interface aaa
{
TRESULT bbb<T, TRESULT>(T n);
}

class AAA : aaa
{
public TRESULT bbb<T, TRESULT>(T n)
{
throw new NotImplementedException();
}
}
2022/02/11(金) 22:30:29.44ID:Wu/zW80b0
>>69
欲しいのは本当にinterfaceか?って疑問が出るが

ジェネリクスinterfaceの定義方法は(System.Collections.Generic.)IEnumerableの定義を見に行けばなんとなく分かるとは思う

あとinterfaceはinterfaceからしか継承できない

>>65の書き方だとジェネリクスclassになりそう
2022/02/11(金) 22:34:33.50ID:w2aWSXHv0
Dictionary<string, Func<object, object>>ではだめなのか
2022/02/12(土) 08:20:21.64ID:X2Srr7cu0
>>64
それが1番分かりやすくて単純だ
2022/02/12(土) 17:09:02.11ID:HCWO3i2I0
.net 6で、DataGridViewにDataSourceをバインドして表示する時、
データ量が多い(約24万レコード)と一時的に応答なしになります。
※データ取得は別スレッドで行っています。

サブフォームで表示しており、処理中はメインフォームも応答なしになりますが、
メインフォームとサブフォームを別スレッドにするみたいなのは無理ですか?
2022/02/12(土) 17:25:09.00ID:XcSi1DQ3a
VirtualMode=true
にする。その他もろもろ処理加える必要あるからぐぐれ
2022/02/12(土) 18:34:31.92ID:X2Srr7cu0
>>76
>>77が言ってるように仮想モードを使うんだよ。グリッドで見えてる部分だけを読み込む。
サンプルコードがMSDNのサイトにあるから頑張って実装してくれ。
2022/02/12(土) 21:15:10.31ID:wWgyF7+Aa
窓を閉じたときに
MethodInvokerの中の処理がまだ実行中で例外出すんだけど

停止させるか完了するまでフォームの廃棄を待つ方法は無いの?
2022/02/12(土) 21:27:27.68ID:C+pjCsCl0
一旦FormClosingでキャンセルしたあと完了してから改めてCloseする
2022/02/13(日) 12:57:34.90ID:5Mv4IyiB0
>>69
Genericだとコンパイル時点で型決定する必要があるから、色々な型に対応させたいとかなると
>>74が言ってるみたいにobjectにするか、dynamicにでもするしかない
2022/02/13(日) 14:18:56.36ID:3OIdnfKh0
>>81
嘘教えんな
ジェネリクス定義側はFunc<T, TResult>みたいにコンパイルに型決まってないだろうが

Func<object, object> とかいうクソみたいな型を使わせようとするな
2022/02/13(日) 14:35:33.11ID:TxpWrVyK0
dic.Add("a", (int a) => a * 2);
dic.Add("b", (string b) => b + b);
をやりたいって質問であるという想定なんでしょ?
2022/02/13(日) 14:40:02.85ID:5Mv4IyiB0
>>82
なら出来るやり方言ってみろよ
2022/02/13(日) 14:40:38.46ID:3OIdnfKh0
いろんな型のFuncを受け付けるようにするならそれ用のclassを作ってしまった方が手っ取り早い

public class MyDictinary<T, TResult> : Dictinary<string, Func<T, TResult>{...}

Funcをなんでも受け付けるようにするなら
public class MyDictinary<TDelegate> : Dictinary<string, Func<T, TResult> where TDelegate: Delegate {...}

どうしてもinterfaceにしなくちゃいけないなら
public interface IMyDictinary<T, TResult> : IDictinary<string, Func<T, TResult>{...}


ごちゃ混ぜのFuncを受け付けるようにするとFunc呼び出し時に大変な思いをするだけだからやらん方がいい
2022/02/13(日) 14:46:43.73ID:ifSJDHUhM

>>69はDictionaryいっこにいろんな引数型/戻り値のFuncを入れたいと言ってるみたいだから>>81しかないと思うんだけど・・・
引数型/戻り値型毎に別々のDictionaryにするだけなら、たとえば
var dic1 = new Dictionary<string,Func<int, string>>();
var dic2 = new Dictionary<string,Func<int, int>>();
var dic3 = new Dictionary<string,Func<string, string>>();
みたいにT/TResultの組み合わせに応じて別変数にするだけで解決するような・・?
なんでわざわざ>>85みたいなclassなりinterfaceなりを作る必要があるのかわからない
2022/02/13(日) 14:48:17.51ID:5Mv4IyiB0
>>85
それで違う型の引数のdelegateどうやって突っ込むつもりだ?
アホなのか
2022/02/13(日) 14:54:01.04ID:3OIdnfKh0
マジで1つのインスタンスに別の型のdelegateが入ればなんでもいい前提なん?

取り出して呼び出すときに引数/返り値型調べないといけないが
2022/02/13(日) 14:56:56.20ID:+oV/29aBd
DynamicInvoke使えばいい
2022/02/13(日) 15:19:09.62ID:ifSJDHUhM
ていうか>>85ってコンパイル通る?
「>」ひとつ付け忘れとかDictionaryのミススペルはともかくとして、
2つめの書き方でT/TResultの型はどこから決まるんだろう?

それとも
public class MyDictinary<TDelegate> : Dictionary<string, TDelegate> where TDelegate: Delegate { }
を意図してるのだろうか
Func<object, object>をクソと言ってるからには引数1つの制約すらつかなくなるこんなクソ以下の書き方を意図してるとも思えないけど・・・
2022/02/13(日) 15:28:36.94ID:5Mv4IyiB0
そもそも、そのDictionary使って何したいかまでは知らんから
それを言えば、もう少しマシな案なりが出てくるとは思うが
2022/02/13(日) 15:30:03.46ID:3OIdnfKh0
>>90
携帯からやったから酷いミスしてるのは悪かった

T/TResultの型を決めないならって意図で書いてる
当然Func<object, object>と同じで使うときに酷い目に遭うが

Func<object, object> だと引数型がobjectを受け付けないといけない縛りができるから
「いろんな関数を受け付ける」という要件を満たせない

Delegateだとその縛りはなくなる
ラムダを受け付けられなくなるが
2022/02/13(日) 15:34:09.27ID:Igq9caCG0
質問者は
1つのDictionaryの中に異なる型を混在させたいという話をしてるのか
1つのDictionaryの中は同じ型のみ入るが、型が異なる複数のDictionaryをジェネリックで統一して扱いたいという話をしてるのか

前者ならジェネリックを使うケースではなさそう
2022/02/13(日) 16:07:38.09ID:5Mv4IyiB0
単純なインターフェース使う例だとこんなもんかな
受け取る結果の型が決まってるなら、dynamic使わんで済むけど
public interface IJob
{
dynamic Run();
}

public class SomeJob<T1, T2> : IJob
{
public T1 Param1 {get;}
public T2 Param2 {get;}

public SomeJob(T1 param1, T2 param2)
{
Param1 = param1;
Param2 = param2;
}
public dynamic Run() => (dynamic)Param1 + (dynamic)Param2;
}

public static void Main()
{
var dic = new Dictionary<string, IJob>()
{
{"a", new SomeJob<int, double>(2, 3.3) },
{"b", new SomeJob<float, double>(5.5f, 16.612340) },
};
Console.WriteLine(dic["a"].Run());
Console.WriteLine(dic["b"].Run());
}
2022/02/13(日) 16:11:15.84ID:5Mv4IyiB0
SomeJobをジェネリックにしたけど、別にIJobを実装したクラス個別に作っても構わない
2022/02/13(日) 17:02:55.32ID:7+Po28QvM
わざわざinterfaceを定義する意味がわからん
たぶん>>94はdynamic型にキャストしたデリゲートを直接呼び出せることを知らないんだろう
2022/02/13(日) 17:24:19.17ID:5Mv4IyiB0
さすがにそれは判るわw
>>69でinterfaceが判らんって書いてるからサンプルで出しただけ
2022/02/13(日) 17:47:23.01ID:DvSkIP620
別にインターフェイスを使いたいってわけじゃないだろ

var dic = new Dictionary<string, Delegate>();

Func<int, int> f1 = (i => i + 1);
Func<string, string> f2 = (s => s + "さん");
dic.Add("1", f1);
dic.Add("2", f2);

Console.WriteLine(dic["1"].DynamicInvoke(2));
Console.WriteLine(dic["2"].DynamicInvoke("名無し"));

これでいいんじゃないか
2022/02/13(日) 19:33:32.60ID:gSu1aBn10
>>98
なんかすげーなまじで
仕事で使ってるだけのわいには到底思いつかんわ

しかしこれなんか業務で使える場面あるん?
2022/02/13(日) 19:55:15.91ID:DvSkIP620
>>99
本当は何がやりたいかは知らんわ

>Dictionary<string, Func<T, TRESULT>>
>みたいな事をやりたいのですが
って話だからな
2022/02/13(日) 20:48:10.88ID:7zxfmdEw0
本当にやりたいことを突き詰めるとそんな面倒なことをしなくてもよい解決方法があったりするのはよくある事よな
今回の件でも当てはまるかどうかは知らんけど
2022/02/15(火) 12:56:44.30ID:XMXX+kQj0
例えばFFMPEGをC#で起動させてるときに
エンコード処理みたいな定期的に値が返ってくるやつって
別スレッドでFFMPEGを走らせて
本スレッドではテキストボックスあたりに出力するようにしたいんだけど
これってFFMPEGの処理が終わるまでメインスレッドはwaitしないとダメってことですよね?

単独スレッドで終了した結果は表示できるんですけど
2022/02/15(火) 13:01:30.90ID:XQ5fPZCEa
そんなことはない
別スレッドで読みだした値をメインスレッドに送って、メインスレッドでその値を表示すればいい
別スレッドからUIに表示しようとしたらエラーになる
2022/02/15(火) 17:00:40.59ID:/St4XHrW0
>>102
本スレッドのTextBox.TextにInvoke使って書き込むんだよ
2022/02/15(火) 19:16:59.08ID:jLK4fSzed
たぶんGUIアプリ作ってるんだろうけど
GUIのデータはメインスレッドしか書き換えちゃダメなルールがある

TextBox.Invokeでメインスレッドに自分のデータ変えてくれってお願いするか、
WPFのBindingならメインスレッドがデータ持ってないからデータ取りに来いってできたりする
2022/02/15(火) 19:24:23.63ID:IqKJXua+0
今のc#はスレッドを安易に使えるがスレッドには深い闇がある。
107名無し募集中。。。 (ワッチョイ ffad-aF3f)
垢版 |
2022/02/20(日) 04:59:16.93ID:gLgXgTw20
c#ってvisual studio でテストする時って
アプリの前回値みたいの記憶できないの?
〇〇フォルダのパスとか記憶したいんだけど
108デフォルトの名無しさん (JP 0H1f-JnE0)
垢版 |
2022/02/20(日) 05:45:33.44ID:9eA/EulNH
Windows上だと何日動かしてもメモリ使用量40MBくらいで安定してるプログラムが
(VS2002の診断ツールで確認)

ラズパイのMono上だと徐々にメモリ使用量が増え続けて
1日くらいで4GB到達して落ちるんだけど何故だろう
109デフォルトの名無しさん (アウアウウー Sae7-iDSx)
垢版 |
2022/02/20(日) 08:10:15.15ID:k8LvFvhxa
タイマーかなんか仕掛けて手動で↓を呼ぶ
GC.Collect(2, GCCollectionMode.Forced, false, true);

それで減らないならMonoのランタイムがそもそもUNCOと思われ。

Unity Profilerで表示されるMonoで使用メモリ量が膨大になってしまう
https://teratail.com/questions/238133
2022/02/20(日) 08:11:50.49ID:/uCWXFvO0
VS2002?
2022/02/20(日) 15:59:54.94ID:gLgXgTw20
dataGridView の中のリストの大きさってどうやって変えるの?
枠の大きさは変えられるんだけど
中のリストだけ小さいままでこまってる
2022/02/20(日) 23:16:48.82ID:ppLUrwgj0
中のリストという意味がちょっと判らない、列や行の幅の事?
名前にWidthとかHeightが含まれるプロパティ片っ端から弄ってみたら
113デフォルトの名無しさん (アウアウウー Sae7-7p3p)
垢版 |
2022/02/21(月) 19:22:27.56ID:4hCK79/5a
var form = new Form(){
 Text = "たいとる"
 FormBorderStyle = FormBorderStyle.FixedDialog
};

みたいに書けるやつ
一見VBのwith文っぽいけどプロパティの代入行為しかできなくて中途半端
2022/02/22(火) 10:14:36.95ID:Q9cfD2FD0
そら、初期化のために用意されているものなんだからそういうもんだろ
2022/02/22(火) 13:36:13.33ID:j1m5S7Tk0
オブジェクト初期化子って名前を知らないとwith的なもんかと思ってしまうのかも知れないね
2022/02/22(火) 15:45:45.85ID:vNlU0s1vM
VBのWith文読み難いから出来んでいい
2022/02/22(火) 15:53:33.83ID:PEuqNSu60
vb.netのオブジェクト初期化子はWithなんだよね。
冗長だ。
2022/02/22(火) 16:15:23.63ID:gr38xJ4ba
c#のは同じような書き方でも意味が変わって一貫性のようなものがない(ように一見思える)
var form = new Form()
{Text = Text};
form.click += delegate
{Text=Text;};

vbのは普通の命令としてもwithがあり、そこに囲まれてる変数の頭にピリオドを付けるという書き方の一貫性のようなものがあるからな
どっちが初心者に優しいかと言えば今でもvbと感じる(vbがいいとは言ってない)
119デフォルトの名無しさん (ワッチョイ 6fe9-EcOz)
垢版 |
2022/02/23(水) 12:07:24.23ID:n7YEN9KD0
フレームワークの話でしょうが、フォームアプリでモーダルフォームの外を
クリックした時に、モーダルフォームを閉じる事って出来るでしょうか?
スマホのUIによくある挙動ですが、同等の動きを実現出来ないかなと。
120119 (ワッチョイ 6fe9-EcOz)
垢版 |
2022/02/23(水) 12:10:24.55ID:n7YEN9KD0
初心者板の内容でした。
失礼しました。
2022/02/23(水) 12:26:47.20ID:n4QLtIZ70
薄毛や抜け毛にお悩みなら、発毛専門の*****へ。
一人ひとりの薄毛・脱毛原因を正確に突き止め、その原因を解消する独自の発毛システムを提供しています。
2022/02/23(水) 19:02:33.81ID:wKfqGXJ00
たぶん画面全体に、透明のレイヤーでも貼るのだろう

それで、そのレイヤーがクリックイベントを受け取れる
123デフォルトの名無しさん (ワッチョイ cf10-hSEA)
垢版 |
2022/02/23(水) 20:18:19.67ID:Mz9SDh4V0
すいません 教えてください
文字列変数の中に 変数をしてしておいて 実行時に指定する方法ありますか?

例:
目覚まし時計プログラムで
9:00の時
9:00になりました。 おはようございます。
12時の時
お昼です 12:00になりました。
って 入れ替えたいのだけど
$Time になりました。おはようございます。

12時の時の文字列は
お昼になりました$Timeになりました。

って指定しておき $Timeをあとから指定したいみたいな方法です。
2022/02/23(水) 20:28:47.29ID:RBoSgh/A0
Replace("$Time", "12:00")
2022/02/23(水) 20:56:09.29ID:77XR+UNq0
>>123
お望みなのは、文字列補間?

string a="かきくけこ";
Console.WrightLine($"あいうえお { a } さしすせそ");
2022/02/23(水) 21:57:54.53ID:6Rc20OyP0
埋め込む文章も変えたいみたいだから
DateTimeによって適したフォーマット用文字列を返すようにして、その後string.Format()するとか
2022/02/24(木) 06:20:18.96ID:1wBDmGBO0
>>122
Webじゃないから難しいかな
2022/02/24(木) 10:51:32.90ID:N/yjILul0
>>119
フックしちゃうのは?
https://www.artistics.co.jp/blog/2019/07/1485/
2022/02/24(木) 21:50:55.08ID:G5PhgONP0
>>119
Deactivateイベントで拾えないか?
130デフォルトの名無しさん (ワッチョイ cf10-iDSx)
垢版 |
2022/02/24(木) 22:02:34.13ID:eVS3l/k90
>>126 ありがとうございます。
一つ進化しました。
求めているのは、 126みたいな感じです。
2022/02/25(金) 14:06:14.20ID:Eg3DloqN0
Ruby on Rails では、ERB(Embedded Ruby)で、何の文書にも、Rubyのコード片を埋め込める

例えば、a.rb 内で、ary = [ "a", "b" ]
と定義して、ERB のresult( binding )で、
この文脈を他のファイルへ、バインドできる

b.html.erb 内で、<% 〜 %>, <%= 〜 %> を使って、Rubyのコード片を埋め込む

<% ary.each do | elem | %>
<p><%=h elem %></p>
<% end %>

出力ファイル、b.html
<p>a</p>
<p>b</p>

他にも、カスタムフォーマットを自作して、その形式を日本語辞書に登録して、呼び出せる

ja:
time:
formats:
medium: "%Y年%m月%d日 (%a) %H:%M"

と定義したら、b.html.erb 内で、
<%=l( Time.current, format: :medium ) %>
と書くと、

出力ファイル、b.html
2022年02月25日 (金) 13:55

まあ、コミュニティーが配布している日本語辞書に、
最初から、幾つかの形式が登録されているから、自作する事は少ない
2022/02/25(金) 15:06:52.58ID:8px/N21n0
Rubyって使ったことなかったけど、
それAsp.netにそっくりやね
2022/03/01(火) 13:52:40.14ID:4BvRS+UW0
Console.writeline()はスレッドセーフでないというのは本当でしょうか?
今までシングルスレッドで動いていたプログラムを一部の処理だけマルチスレッドで動作するように変更中です
Console.writeline()の呼び出し箇所を全て変更する必要がありますか?
2022/03/01(火) 13:56:54.75ID:VTZdDdWR0
スレッドセーフです
2022/03/01(火) 20:21:42.35ID:OUtPpYxS0
https://docs.microsoft.com/ja-jp/dotnet/api/system.console?view=net-6.0#thread-safety
2022/03/01(火) 23:40:13.90ID:wsOShTVj0
この方は スレッガー ロウ です
2022/03/15(火) 17:49:18.74ID:uT8cdwkS0
相談させてください。

IntPtr を ref int に変換するために以下のようなコードを書くと、期待通り False と表示されます。

IntPtr ptr = Marshal.AllocCoTaskMem(4);
ref int x = ref Unsafe.AddByteOffset(ref Unsafe.NullRef<int>(), ptr);
Console.WriteLine(Unsafe.IsNullRef(ref x)); // False と表示される
Marshal.FreeCoTaskMem(ptr);

しかし、以下のように意味のない for 文を追加すると、コードの最適化が有効な場合のみ True と表示されます。

for (int i = 0; i < 0; i++) { } // 意味のない for 文
IntPtr ptr = Marshal.AllocCoTaskMem(4);
ref int x = ref Unsafe.AddByteOffset(ref Unsafe.NullRef<int>(), ptr);
Console.WriteLine(Unsafe.IsNullRef(ref x)); // 最適化が有効な場合のみ True と表示される
Marshal.FreeCoTaskMem(ptr);

ただし、意味のない for 文があっても
Unsafe.AddByteOffset(ref Unsafe.NullRef<int>(), ptr)
→ Unsafe.SubtractByteOffset(ref Unsafe.NullRef<int>(), -(nint)ptr)
のように書き換えると常に False と表示されるようになります。

なぜこのようなことが起こるのかさっぱり見当がつかないので、お知恵を拝借できないでしょうか。
私の環境を分かる範囲で書くと以下のとおりですが、他に何か必要な情報があればお教えください。

Windows 10 Pro (21H2)
Microsoft Visual Studio Community 2022 (64 ビット) Version 17.1.1
コンソール アプリケーション、.NET 6.0

どうぞよろしくお願いいたします。
2022/03/15(火) 18:02:33.05ID:LD6RLXEha
一行目しか見てないけど、これはいいのか?(8)かもよ
IntPtr ptr = Marshal.AllocCoTaskMem(4);
2022/03/15(火) 18:57:03.19ID:BlmPXv890
そもそも現在のポインタ値がヌル参照からのオフセットだって保証されてるのか?
2022/03/15(火) 18:59:03.73ID:1RknuKaK0
for文に意味があるからじゃないかな
2022/03/15(火) 20:05:41.25ID:NI5jmOXt0
最適化でなんか情報が消し飛んでるんだと思うけど、判らんな
[MethodImpl(MethodImplOptions.NoInlining)]
public static ref T AddByteOffset<T>(ref T reference, IntPtr offset)
=> ref Unsafe.AddByteOffset(ref reference, offset);
とかやってインライン展開抑制してみたら
2022/03/15(火) 21:00:09.00ID:ZTE9InWz0
>>137
JIT最適化を抑制せずF11でデバッグして逆アセンブルすると
先にConsole.WriteLine(Boolean)がTrue固定で呼び出されて
その後にMarshal.IsNullOrWin32Atom(IntPtr)となってるね

未定義動作はタイムトラベルを…彷彿とさせるがC#なんだよなぁ
MSIL的にも&とnative intの結果型は&に定められている筈だし
とはいえ、管理下ポインタはnullになりえないとか有った気もするし
null参照への演算が未定義なら道理なのかもしれない、あるいはバグか
2022/03/15(火) 21:23:35.68ID:uT8cdwkS0
皆様、返信どうもありがとうございます。
いただいたアドバイスを元に色々と確認をしていて反応が遅くなってしまいました。
申し訳ありません。

>>138
確認してみた所、C# では int は 32 ビットと決められているようです。
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/builtin-types/integral-numeric-types
ただ、可読性を考えると 4 ではなく sizeof(int) と書くべきでした。
ご指摘どうもありがとうございました。

>>139
Unsafe.NullRef<T>() と Marshal.ReadInt32(int) の実装を確認してみたところ、
おそらくその点は問題ないかと思います。
https://github.com/dotnet/corert/blob/master/src/System.Private.CoreLib/shared/Internal/Runtime/CompilerServices/Unsafe.cs
https://github.com/dotnet/corert/blob/master/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs
しかし、問題の原因は大抵こういう思い込みに隠れているものだと思うので、
可能性を一つ潰すことができてとても助かりました。

>>140
そうなんですよね。
for (int i = 0; i < 0; i++) {} は i++ に到達しないのは明らかだから
最適化でまるっと消えてしまうかと思っていたので、この結果には驚きました。

>>141
書いていただいたコードを試してみたところ、確かに最適化が有効でも期待通りの動作になりました。
それからもう一つ、書いていただいたコードを使わない場合、
プラットフォームが x86 と x64 の両方とも最適化有効時には期待通りの動作をしないことが分かりました。
(x86 の場合は常に期待通りに動作するならば問題の原因について一つ仮説が立てられるかと思ったのですが、
 実際は違っていたので未だに原因はさっぱり見当がついていません…)
2022/03/15(火) 21:24:27.40ID:uT8cdwkS0
>>142
null参照への演算が未定義というのは、AddByteOffset メソッド内の話でしょうか。
下記のページの AddByteOffset<T>(ref T, IntPtr) のところをみると

ldarg.0
ldarg.1
add
ret

とコメントされていて、少なくとも IL 的には一つ目の引数が null でも特に問題はないように思えてしまいます。
IL 的に問題がないかどうかは私は自信がないのですが、
もし IL に問題がないのに JIT 最適化で問題が起きてしまうとすれば、
バグと考えてもよいのでしょうか。

参考
https://github.com/dotnet/corert/blob/master/src/System.Private.CoreLib/shared/Internal/Runtime/CompilerServices/Unsafe.cs
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況