(this == null)C#!
-
05-07-2019 - |
質問
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に投稿されました今日の質問。
マークのその質問に対する優れた回答は、仕様(セクション7.5.7)に従ってはいけないことを示していますそのコンテキストで this
にアクセスできるようになりますが、C#3.0コンパイラでアクセスできるかどうかはバグです。 C#4.0コンパイラは仕様に従って正しく動作しています(ベータ1でも、これはコンパイル時エラーです):
&#167; 7.5.7このアクセス
A this-access は予約語
this
で構成されています。this-access:
this
A this-access は、インスタンスコンストラクター、インスタンスメソッド、またはインスタンスアクセサーのブロックでのみ許可されます。
他のヒント
デバッグモードバイナリの生の逆コンパイル(最適化なしのリフレクタ)は次のとおりです。
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 .locals init (
[0] string CS$1 L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: ret
)
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
;
CS$1<*> = CS$1<*>.CheckNull();
Label_0009:
return CS$1<*>;
}
private string CheckNull()
{
string CS$1<*>;
CS$1<*> = "Am I null? " + ((bool) (this == null));
Label_0017:
return CS$1<*>;
}
}
CompilerGeneratedメソッドは意味がありません。 IL(下)を見ると、null string (!)でメソッドを呼び出しています。
<*>リリースモードでは、ローカル変数は最適化されて除外されるため、存在しない変数をスタックにプッシュしようとします。
<*>(C#に変換するとReflectorがクラッシュします)
編集:コンパイラーが ldloc
を出力する理由を誰もが知っていますか(Eric Lippert?)
それはありました! (そして証拠も得た)
これは「バグ」ではありません。これは、型システムを乱用しています。現在のインスタンスへの参照( this
)をコンストラクター内の誰かに渡すことは決してありません。
同様の&quot; bug&quot;を作成できます基本クラスコンストラクター内でも仮想メソッドを呼び出します。
悪意のあることを できるからといって、それを少しでも手に入れてもバグではありません。
間違っている可能性がありますが、オブジェクトが null
である場合、 this
が適用されるシナリオは決してありません。
たとえば、 CheckNull
をどのように呼び出しますか?
Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
これがあなたが探しているものかどうかわからない
public static T CheckForNull<T>(object primary, T Default)
{
try
{
if (primary != null && !(primary is DBNull))
return (T)Convert.ChangeType(primary, typeof(T));
else if (Default.GetType() == typeof(T))
return Default;
}
catch (Exception e)
{
throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToString() + " instead of " + typeof(T).ToString());
}
return default(T);
}
example:UserID = CheckForNull(Request.QueryString [&quot; UserID&quot;]、147);