(这= = 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中,它没有编译(我没试过Beta 1);我学到了很难的方法
在纯C#中有没有其他方法可以使 this == null
?
解决方案
此观察结果已在另一个发布在StackOverflow上问题今天早些时候。
Marc 的对该问题的答案很好表明根据规范(第7.5.7节),你不应该能够在该上下文中访问 this
,并且在C#3.0编译器中执行此操作的能力是一个错误。 C#4.0编译器根据规范正常运行(即使在Beta 1中,这是一个编译时错误):
<强>&#167; 7.5.7此访问
this-access 由保留字
this
组成。此访问:
this
只允许在实例构造函数,实例方法或实例访问器的块中使用 this-access 。
其他提示
Debug模式二进制文件的原始反编译(没有优化的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 .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 字符串(!)上调用该方法。
<*>在Release模式下,局部变量被优化掉,因此它会尝试将不存在的变量推送到堆栈。
<*>(反射器在转换为C#时崩溃)
编辑:有没有人(Eric Lippert?)知道编译器为什么会发出 ldloc
?
我有那个! (并得到证据)
这不是“错误”。这是你滥用类型系统。您永远不应该将对当前实例( this
)的引用传递给构造函数中的任何人。
我可以创建一个类似的“bug”。通过在基类构造函数中调用虚方法。
仅仅因为你可以做坏事并不意味着当你得到它时, bug 。
我可能错了,但我很确定你的对象是 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);
}
示例:UserID = CheckForNull(Request.QueryString [&quot; UserID&quot;],147);