(this = = null)在 C # 中!

由于在 C # 4中修复了一个 bug,下面的程序将打印 true

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) ; 我是通过艰难的方式学到这一点的

有没有其他方法可以使纯 C # 中的 this == null

14365 次浏览

我可能错了,但是我很确定如果您的对象是 null,那么将永远不会出现应用 this的场景。

例如,如何调用 CheckNull

Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException

我已经得到了! (也得到了证据)

alt text

Debug 模式二进制文件的原始反编译(未经优化的反射器)如下:

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 # 时崩溃)


编辑 : 有人(Eric Lippert?)知道为什么编译器会发出 ldloc吗?

这不是“虫子”。这是你滥用类型系统。不应该将对当前实例(this)的引用传递给构造函数中的任何人。

我也可以通过调用基类构造函数中的虚方法来创建类似的“ bug”。

仅仅因为你的 可以做坏事并不意味着它是一个 臭虫当你被它咬。

今天早些时候,我们已经在 另一个问题的 StackOverflow 上发布了这一观察结果。

Marc 这个问题的答案不错指出,根据规范(7.5.7节) ,您不应该能够在该上下文中访问 this,而在 C # 3.0编译器中这样做是一个 bug。C # 4.0编译器根据规范运行正常(即使在 Beta 1中,这也是一个编译时错误) :

7.5.7此通道

这个,权限由保留字 this组成。

此-进入:

this

只允许在实例构造函数、实例方法或实例访问器的 拦截中使用 这个,权限

不知道这是不是你要找的

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