131

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では、コンパイルされません(Beta 1は試していません)。私は難しい方法を学びました

this == null純粋なC#で作成する他の方法はありますか?

4

6 に答える 6

73

この観察結果は、今日の別の質問で StackOverflow に投稿されています。

その質問に対するMarcの優れた回答は、仕様 (セクション 7.5.7) によるとthis、そのコンテキストでアクセスできないはずであり、C# 3.0 コンパイラでアクセスできることはバグであることを示しています。C# 4.0 コンパイラは、仕様に従って正しく動作しています (ベータ 1 でも、これはコンパイル時エラーです)。

§ 7.5.7 このアクセス

this-accessは、予約語 で構成されますthis

このアクセス:

this

this アクセスは、インスタンス コンストラクター、インスタンス メソッド、またはインスタンス アクセサーのブロックでのみ許可されます。

于 2009-10-21T13:13:16.827 に答える
24

デバッグ モード バイナリの生の逆コンパイル (最適化なしのリフレクター) は次のとおりです。

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 (以下) を見ると、null文字列(!) でメソッドを呼び出しています。

   .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# に変換するとクラッシュします)


EDIT : 誰か (Eric Lippert?) が、コンパイラが ? を出力する理由を知っていldlocますか?

于 2009-10-21T13:09:14.447 に答える
11

私はそれを持っていました!(そして証拠も得た)

代替テキスト

于 2009-10-21T13:08:01.997 に答える
10

これは「バグ」ではありません。これは、型システムを悪用しています。this現在のインスタンス ( ) への参照をコンストラクター内の誰にも渡してはいけません。

基本クラスのコンストラクター内でも仮想メソッドを呼び出すことで、同様の「バグ」を作成できます。

何か悪いことをすることができるからといって、それに噛まれたときにそれがバグであるとは限りません。

于 2009-10-21T13:09:22.757 に答える
3

私は間違っている可能性がありますが、あなたのオブジェクトが存在する場合、適用されるnullシナリオは決してないだろうと確信しています。this

たとえば、どのように呼びCheckNullますか?

Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
于 2009-10-21T12:59:31.640 に答える
-1

これがあなたが探しているものかどうかわからない

    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);
    }

例: UserID = CheckForNull(Request.QueryString["UserID"], 147);

于 2010-05-07T16:16:40.127 に答える