C#4で修正されたバグのため、次のプログラムはtrue
を出力します。 (LINQPadで試してください)
void Main() { new Derived(); }
class Base {
public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
}
class Derived : Base {
string CheckNull() { return "Am I null? " + (this == null); }
public Derived() : base(() => CheckNull()) { }
}
リリースモードのVS2008では、InvalidProgramExceptionがスローされます。 (デバッグモードでは、正常に動作します)
VS2010 Beta 2では、コンパイルされません(ベータ1は試しませんでした)。私はその難しい方法を学びました
純粋なC#でthis == null
を作成する他の方法はありますか?
この所見は、StackOverflowの 別の質問 に今日投稿されました。
Marc の その質問に対する素晴らしい回答 は、仕様(セクション7.5.7)に従って、this
にアクセスできないことを示します。そのコンテキストと、C#3.0コンパイラでこれを行う機能はバグです。 C#4.0コンパイラは仕様に従って正しく動作しています(ベータ1でも、これはコンパイル時エラーです)。
§7.5.7このアクセス
this-accessは予約語
this
で構成されます。this-access:
this
this-accessは、インスタンスコンストラクター、インスタンスメソッド、またはインスタンスアクセサーのblockでのみ許可されます。
デバッグモードバイナリの生の逆コンパイル(最適化なしのリフレクタ)は次のとおりです。
private class Derived : Program.Base
{
// Methods
public Derived()
{
base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
return;
}
[CompilerGenerated]
private static string <.ctor>b__0()
{
string CS$1$0000;
CS$1$0000 = CS$1$0000.CheckNull();
Label_0009:
return CS$1$0000;
}
private string CheckNull()
{
string CS$1$0000;
CS$1$0000 = "Am I null? " + ((bool) (this == null));
Label_0017:
return CS$1$0000;
}
}
CompilerGeneratedメソッドは意味がありません。 IL(下)を見ると、nullstring(!)でメソッドを呼び出しています。
.locals init (
[0] string CS$1$0000)
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: stloc.0
L_0007: br.s L_0009
L_0009: ldloc.0
L_000a: ret
リリースモードでは、ローカル変数は最適化されて除外されるため、存在しない変数をスタックにプッシュしようとします。
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: ret
(C#に変換するとReflectorがクラッシュします)
[〜#〜] edit [〜#〜]:誰かが(Eric Lippert?)コンパイラがldloc
を出力する理由を知っていますか?
私はそれを持っていました! (そして証拠も得た)
これは「バグ」ではありません。これは、型システムを乱用しています。現在のインスタンス(this
)への参照をコンストラクター内の誰にも渡すことは決してありません。
基本クラスコンストラクター内でも仮想メソッドを呼び出すことで、同様の「バグ」を作成できます。
あなたがcan悪いことをするからといって、それがbugになったからといってそれが意味するわけではありません。
私は間違っているかもしれませんが、あなたのオブジェクトがnull
である場合、this
が適用されるシナリオは決してないでしょう。
たとえば、CheckNull
をどのように呼び出しますか?
Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException