null检查何时可以引发NullReferenceException



我知道一开始这可能看起来不可能,一开始我也觉得是这样,但最近我看到了这种代码抛出NullReferenceException,所以这绝对是可能的。

不幸的是,谷歌上几乎没有任何结果可以解释像foo == null这样的代码何时会抛出NRE,这可能会使调试和理解为什么会发生这种情况变得困难。因此,为了记录这种看似奇怪的事件可能发生的方式。

这个代码foo == null可以通过什么方式抛出NullReferenceException

在C#中,您可以重载运算符,以便在类似这样的比较中添加自定义逻辑。例如:

class Test
{
public string SomeProp { get; set; }

public static bool operator ==(Test test1, Test test2)
{
return test1.SomeProp == test2.SomeProp;
}
public static bool operator !=(Test test1, Test test2)
{
return !(test1 == test2);
}
}

那么这将产生一个空引用异常:

Test test1 = null;
bool x = test1 == null;

一个例子是getters:

class Program
{
static void Main(string[] args)
{
new Example().Test();
}
}
class Example
{
private object foo
{
get => throw new NullReferenceException();
}
public void Test()
{
Console.WriteLine(foo == null);
}
}

此代码将生成一个NullReferenceException。

虽然很深奥,但通过DynamicMetaObject的自定义实现可能会导致这种类型的行为。这将是一个罕见但有趣的例子,说明这种情况可能发生在哪里:

void Main()
{
dynamic foo = new TestDynamicMetaObjectProvider();
object foo2 = 0;

Console.WriteLine(foo == foo2);
}
public class TestDynamicMetaObjectProvider : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new TestMetaObject(parameter, BindingRestrictions.Empty, this);
}
}
public class TestMetaObject : DynamicMetaObject
{
public TestMetaObject(Expression expression, BindingRestrictions restrictions)
: base(expression, restrictions)
{
}
public TestMetaObject(Expression expression, BindingRestrictions restrictions, object value)
: base(expression, restrictions, value)
{
}
public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
{
// note it doesn't have to be an explicit throw.  Any improper property
// access could bubble a NullReferenceException depending on the 
// custom implementation.
throw new NullReferenceException();
}
}

不是你的代码,但等待一个空任务也会抛出:

public class Program
{
public static async Task Main()
{
var s = ReadStringAsync();
if (await s == null)
{
Console.WriteLine("s is null");
}
}
// instead of Task.FromResult<string>(null);
private static Task<string> ReadStringAsync() => null;
}

但是,请注意,调试器可能会错误地获取抛出语句的位置。它可能会显示在相等性检查时抛出的异常,而它发生在早期代码中。

foo == null确实对运算符重载进行了解析,并且有问题的运算符没有处理被传递的null。我们开始考虑将foo == null写为过时的,并且更喜欢(从Visual Basic中取一页(foo is null或即将成为full is not null!(foo is null)显式内联空指针检查。

修复您的operator==实现。它不应该扔,但它是。

相关内容

  • 没有找到相关文章

最新更新