C#で「void」がジェネリック型として許可されないのはなぜですか


53

void構築可能でなく、ジェネリック型として許可されないことを支持して設計上の決定は何でしたか?結局それだけで特別な空であるstructと明確な持つの合計PITA避けているだろうFuncし、Actionデリゲートを。

(C ++は明示的なvoid戻り値を許可voidし、テンプレートパラメータとして許可します)


13
@Oded Eric Lippertにはアカウントがあり、Programmers参加していることを考えると、彼はちょうどやったと思います。
トーマスオーエンズ

2
@BenVoigt必ずしも単一の個人の知識を必要とするわけではありませんが、ここには単一の正しい答えを与えることができる(簡単に推測できます)単一の人がいます。特にプログラミング言語の設計の知識がある場合は、仕様に精通している人なら誰でもおそらく質問に答えることができます。また、興味深い言語設計/言語実装の質問でもあります。これはここで取り上げます。
トーマスオーエンズ

6
@BenVoigt:正当な理由もなく完全に有効で興味深い質問を閉じたいと思うのはなぜですか?私は検索しましたが、答えが見つかりませんでした。多分ここの誰かがそれについてのブログ投稿を読んだかもしれません、多分、決定を下した人は質問に答えたいと思っているかもしれません。人々は質問に答えるよりも質問を閉じてもらうことにずっと興味があるように見えるので、私はこのサイトへの投稿をやめました。

4
ここで、特にSOに関する「大きなポイント」の質問と回答は、一般に「この構文はどういう意味ですか?」という形式です。誰でもconst poinersの定義を積み上げてオブジェクトをconstにできるため、これらの質問はほとんど解決されません。打ちのめされたトラックから外れたより興味深い質問は、いくつかの退屈な理由でサイトから探し出されます:真剣に、それはどこかのデータウェアハウスでほんの数キロバイトです。目的をほとんど果たさないarbitrarily意的に解釈されたルールを課すのではなく、ただリラックスして学習を受け入れることができますか?

2
@ThomasOwens:私はある意味、SOよりもこのサイトで積極的に活動しています。このサイトでは、300ごとに約1つの質問への回答を投稿します。SOでは、1500ごとに約1つの質問への回答を投稿します。 SOでC#の質問に答えます。
エリックリッパー

回答:


69

「void」の基本的な問題は、他の戻り値型と同じことを意味しないことです。「void」は、「このメソッドが戻る場合、値をまったく返さない」ことを意味します。ヌルではありません。nullは値です。値をまったく返しません。

これは本当に型システムを台無しにします。型システムは、本質的に、特定の値に対して有効な操作を論理的に推論するためのシステムです。voidを返すメソッドは値を返さないため、「この操作で有効な操作は何か?」まったく意味がありません。有効または無効の操作が行われるための「もの」はありません。

さらに、これにより、ランタイムが非常に激しくなります。.NETランタイムは、スタックマシンとして指定された仮想実行システムの実装です。つまり、評価スタックへの影響という点ですべての操作が特徴付けられている仮想マシン。(もちろん、実際にはマシンはスタックとレジスタの両方を備えたマシンに実装されますが、仮想実行システムはスタックのみを想定しています。)voidメソッドの呼び出しの効果は基本的に非voidメソッドの呼び出しの効果とは異なります。非voidメソッドは常にスタックに何かを置くため、ポップする必要があるかもしれません。voidメソッドは、スタックに何かを置くことはありません。したがって、コンパイラは、メソッドの戻り値が無視される場合、voidメソッドと非voidメソッドを同じように処理できません。メソッドがvoidの場合、戻り値はないため、ポップはありません。

これらすべての理由から、「void」はインスタンス化できる型ではありません。がありません。それがポイントです。オブジェクトに変換することはできません。また、voidを返すメソッドは、voidを返さないメソッドで多態的に扱うことはできません。

したがって、voidを型引数として使用することはできません。これは、ご存知のように残念です。とても便利でしょう。

後知恵の恩恵により、ボイドを返すメソッドが魔法のシングルトン参照型である「Unit」を自動的に返した場合、何もするのではなく、関係者全員にとってより良いことでした。その後、すべてのメソッド呼び出しがスタックに何かを置くことを知っているでしょう、あなたはすべてのメソッド呼び出しがオブジェクト型の変数に割り当てることができる何かを返すことを知っているでしょう、そしてもちろんUnitは型引数として使用できるので、 ActionおよびFuncデリゲートタイプを個別に持つ必要はありません。悲しいことに、それは私たちがいる世界ではありません。

この流れについてのさらなる考えについては、以下を参照してください。


C ++は、魔法のシングルトン型を使用せずにサポートします。しかし、C#とはまったく異なる「ジェネリック」スタイルを使用するC ++に関係していると思います。
ウィンストン

4
@WinstonEwert-C ++はジェネリックをまったくサポートしておらず、根本的に異なるテンプレートを持っていると確信しています。私が理解しているように、テンプレートを使用すると、コンパイラはグローバル検索を実行して型パラメーターに置き換えますが、ジェネリックを使用すると、型システムは適切な型を作成します。それが、C ++テンプレートエラーがそれほど鈍い理由でもあると思います。私は私ではない全く正しい何かを言っている場合エリックは私を修正します確信している
アダムRackis

1
すべての構造体はコンパイル時に処理され、スタックやその他のインライン化された場所に適切に配置されると思います。したがってVoid、0スタックバイト内で無限量の引数として渡されても問題ありません。構造体の変換objectまたはメソッドの取得(取得this)が必要な場合Type、メモリのフィールド領域の前に参照を挿入してヒープに配置してボックス化し(多くのCLR実装の場合)、適切に処理できます。私に関しては、タイプは、いくつかの特性(フィールド)によって区別できるオブジェクトのグループ化にすぎません。Voidただ一つのオブジェクトです。
ONY

1
@ OlivierJacot-Descombes:void空の値型の場合、そのステートメントはマシンコードのゼロ命令に変換されます。のハードコードされた型にはあまり有用ではありませんVoidが、型に複数のジェネリックパラメーターがあるが、特定の場合には一部のパラメーターが不要な場合に役立ちます。
supercat

2
@EricLippert:値型の戻り値を適切に処理するには、スタックから可変数の単語をポップする機能が必要です。単語の数をゼロにするのに根本的な困難はありますか?呼び出し側がスペースの割り当てとbyrefの受け渡しを担当する場合、型システムはvoid byrefには意味がないことを認識しなければならず、おそらくそれは努力する価値があるとは見なされませんでしたが、「基本的な」問題は見当たりません。
supercat

9

From:http : //connect.microsoft.com/VisualStudio/feedback/details/94226/allow-void-to-be-parameter-of-generic-class-if-not-in-c-then-just-in-ランタイム

これは実際には設計によるものです-void型のインスタンスは許可されません(ランタイムでは他の多くの型と一緒に)。また、voidまたはvoid []をCreateInstanceすることもできません。セキュリティのためにこれらのタイプの穴を塞いだ。

私の人生では、ボイドがセキュリティホールであるかどうかはわかりませんが、...と言っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.