在C#中,当您在null对象上调用扩展方法时会发生什么?

时间:2009-05-11 08:35:28

标签: c# parameters null extension-methods

是否使用空值调用方法,或者它是否提供空引用异常?

MyObject myObject = null;
myObject.MyExtensionMethod(); // <-- is this a null reference exception?

如果是这种情况,我将永远不需要检查我的'this'参数是否为null?

8 个答案:

答案 0 :(得分:352)

这样可以正常工作(也不例外)。扩展方法不使用虚拟调用(即它使用“call”il指令,而不是“callvirt”),因此除非您在扩展方法中自己编写,否则不会进行空值检查。在少数情况下,这实际上很有用:

public static bool IsNullOrEmpty(this string value)
{
    return string.IsNullOrEmpty(value);
}
public static void ThrowIfNull<T>(this T obj, string parameterName)
        where T : class
{
    if(obj == null) throw new ArgumentNullException(parameterName);
}

从根本上说,对静态调用的调用是非常直接的 - 即

string s = ...
if(s.IsNullOrEmpty()) {...}

变为:

string s = ...
if(YourExtensionClass.IsNullOrEmpty(s)) {...}

显然没有空检查。

答案 1 :(得分:48)

除了Marc Gravell的正确答案。

如果显然该参数为null,则可以从编译器收到警告:

default(string).MyExtension();

在运行时运行良好,但会产生警告"Expression will always cause a System.NullReferenceException, because the default value of string is null"

答案 2 :(得分:20)

正如您已经发现的那样,因为扩展方法只是美化的静态方法,所以在传入null引用的情况下调用它们,而不会抛出NullReferenceException。但是,因为它们看起来像调用者的实例方法,所以它们也应该表现。然后,您应该在大多数情况下检查this参数,如果它是null则抛出异常。如果方法明确处理null值并且其名称适当地表示它,则可以不执行此操作,如下例所示:

public static class StringNullExtensions { 
  public static bool IsNullOrEmpty(this string s) { 
    return string.IsNullOrEmpty(s); 
  } 
  public static bool IsNullOrBlank(this string s) { 
    return s == null || s.Trim().Length == 0; 
  } 
}

我前段时间也写过a blog post

答案 3 :(得分:14)

null将传递给扩展方法。

如果方法试图访问该对象而不检查它是否为null,则是,它将引发异常。

这里的一个人写了“IsNull”和“IsNotNull”扩展方法,检查是否传递null。就个人而言,我认为这是一种失常,不应该看到光明,但它完全有效c#。

答案 4 :(得分:6)

正如其他人所指出的那样,在null引用上调用扩展方法会导致this参数为null,并且不会发生任何其他特殊情况。这提出了使用扩展方法编写保护子句的想法。

您可以阅读本文的示例:How to Reduce Cyclomatic Complexity: Guard Clause简短版本是:

**executed code**

这是字符串类扩展方法,可以在空引用上调用:

public static class StringExtensions
{
    public static void AssertNonEmpty(this string value, string paramName)
    {
        if (string.IsNullOrEmpty(value))
            throw new ArgumentException("Value must be a non-empty string.", paramName);
    }
}

调用工作正常,因为运行时将成功调用null引用上的扩展方法。然后你可以使用这个扩展方法来实现guard子句而不会出现凌乱的语法:

((string)null).AssertNonEmpty("null");

答案 5 :(得分:3)

extensionmethod是静态的,所以如果你对这个MyObject没有任何意义,它应该不是问题,快速测试应该验证它:)

答案 6 :(得分:0)

myObject.MyExtensionMethod(); 为 null 时,

myObject 永远不会抛出 Null 引用异常... 但如果 MyExtensionMethod() 没有正确处理 null,它将抛出异常 .

https://dotnetfiddle.net/KqwLya

答案 7 :(得分:-1)

如果您希望自己具有可读性和垂直性,则几乎没有什么黄金法则。

    来自Eiffel的一句话说,封装到方法中的特定代码应该对某些输入起作用,如果满足一些先决条件并保证预期的输出,该代码是可行的

在你的情况下 - DesignByContract已损坏......您将在null实例上执行某些逻辑。