运算符?.和扩展方法

5

使用带有.运算符的扩展方法,即使对象为空也总是会被调用,而不会抛出NullReferenceException。通过使用运算符?.,它将永远不会被调用。例如:

using System;

public class Program
{
    public static void Main()
    {
        A a = null;
        a.b(); // works
        a?.b(); // doesn't work
    }
}

public class A { }

public static class ext
{
    public static void b(this A a)
    {
        Console.WriteLine("I'm called");
    }
}

为什么扩展方法在这种情况下没有被调用?这是一个模糊的特性吗?

2
您可以在Try Roslyn上查看已编译/反编译的代码。 - Kobi
3
“?. ”运算符会在执行任何操作之前先检查值是否为null,那么它为什么有效呢?参考阅读:https://dev59.com/T3RA5IYBdhLWcg3wvQhh 和 https://msdn.microsoft.com/en-us/library/dn986595.aspx - Fabjan
2
拥有一个根本不使用此对象的扩展方法的实际用途是什么? - Yeldar Kurmangaliyev
1
我不明白为什么在a.b();没有出现NullReferenceException - Shaharyar
1
@Shaharyar,因为a上没有任何被调用的内容。 - Paulo Morgado
2个回答

16

使用?.运算符的表达式a?.b()可以翻译为等价的:

if(a != null)
{
  a.b();
}

所以这就是为什么你的方法没有被调用的原因。


1

调用扩展方法有以下边界情况: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#11893-extension-method-invocations

注意:与实例方法调用不同的是,当表达式评估为null引用时将不会抛出异常。相反,这个null值会像常规静态方法调用一样传递给扩展方法。扩展方法的实现决定如何响应此调用。

这就解释了为什么你的编译器会使 a.b() 正常工作(它发出一个 call IL 操作)。并且可以安全地假设 a?.b() 实际上包括运行时空值检查,因此不会执行该方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接