(this == null)在C#中!
由于在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的Release模式下,它会抛出一个InvalidProgramExceptionexception。 (在debugging模式下,它工作正常)
在VS2010 Beta 2中,它不能编译(我没有尝试Beta 1); 我了解到这一点很难
有没有其他的方式来使纯C#中的this == null
?
这个观察已经在今天早些时候的另一个问题的 StackOverflow上发布了。
Marc 对这个问题的很好的回答表明,按照规范(7.5.7节),你不应该能够在上下文中访问this
,而在C#3.0编译器中这样做的能力是一个bug。 C#4.0编译器根据规范正确运行(即使在Beta 1中,这也是一个编译时错误):
§7.5.7这个访问
这个访问由保留字
this
。此访问:
this
只能在实例构造函数,实例方法或实例访问器的块中允许此访问 。
debugging模式二进制的原始反编译(Reflector with no optimizations)为:
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(下面),它将调用空string (!)上的方法。
.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
在释放模式下,局部variables被优化掉了,所以它试图把一个不存在的variables推到堆栈上。
L_0000: ldloc.0 L_0001: call instance string CompilerBug.Program/Derived::CheckNull() L_0006: ret
(reflection器转换成C#时崩溃)
编辑 :有人(Eric Lippert?)知道为什么编译器发出ldloc
?
我已经有了! (也有certificate)
这不是一个“错误”。 这是你滥用types系统。 你永远不应该将一个对当前实例( this
)的引用传递给构造函数中的任何人。
我也可以通过在基类构造函数中调用一个虚拟方法来创build一个类似的“bug”。
只是因为你可以做一些坏事,并不意味着它是一个错误 。
我可能是错的,但我敢肯定,如果你的对象是null
,那永远不会是一个适用的场景。
例如,你将如何调用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); }
例如:UserID = CheckForNull(Request.QueryString [“UserID”],147);