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 编译器按照规范正确运行(即使在 Beta 1 中,这也是编译时错误):

§ 7.5.7 此访问

this-access由保留字组成this

这个访问:

this

仅在实例构造函数、实例方法或实例访问器的块中才允许this访问。

于 2009-10-21T13:13:16.827 回答
24

调试模式二进制文件的原始反编译(Reflector 没有优化)是:

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(如下),它会在空字符串(!) 上调用该方法。

   .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 

在 Release 模式下,局部变量被优化掉,因此它会尝试将一个不存在的变量压入堆栈。

    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret 

(将反射器转换为 C# 时崩溃)


编辑:有谁(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 回答