首页 文章

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

提问于
浏览
285

是使用null值调用方法还是提供null引用异常?

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

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

7 回答

  • 3

    这样可以正常工作(也不例外) . 扩展方法不使用虚拟调用(即它使用“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

    Addition to the correct answer from Marc Gravell.

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

    default(string).MyExtension();
    

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

  • 6

    正如您已经发现的那样,因为扩展方法只是美化的静态方法,所以在传入 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; 
      } 
    }
    

    我前段时间也写了这个.2451424_ .

  • 346

    null将被传递给扩展方法 .

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

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

  • 47

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

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

    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引用上调用的字符串类扩展方法:

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

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

    public IRegisteredUser RegisterUser(string userName, string referrerName)
        {
    
            userName.AssertNonEmpty("userName");
            referrerName.AssertNonEmpty("referrerName");
    
            ...
    
        }
    
  • 19

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

  • 13

    当您希望自己具有可读性和垂直性时,几乎没有什么黄金法则 .

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

    在你的情况下 - DesignByContract被破坏了...你将在null实例上执行一些逻辑 .

相关问题