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

这个方法是否被调用了一个空值,或者它是否给出一个空引用exception?

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

如果是这种情况,我将永远不需要检查我的“这个”参数为空?

这将工作正常(没有例外)。 扩展方法不使用虚拟调用(即它使用“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)) {...} 

那里显然没有空检查。

除了Marc Gravell的正确答案之外。

如果显然这个参数是空的,你可以从编译器得到一个警告:

 default(string).MyExtension(); 

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

正如你已经发现的那样,因为扩展方法是简单的静态方法,所以它们将被传入的null引用被调用,而不引发NullReferenceException 。 但是,由于它们看起来像调用者的实例方法,所以它们也应该如此。 那么你应该在大多数情况下检查this参数,如果它是null ,就抛出一个exception。 如果方法显式地处理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; } } 

我也写了一篇关于这个的博客文章 。

null将被传递给扩展方法。

如果方法试图访问对象而不检查是否为空,那么是的,它会抛出一个exception。

这里的一个人写了“IsNull”和“IsNotNull”扩展方法,检查是否传递null参考。 我个人认为这是一个畸变,不应该看到一天的光,但它是完全有效的C#。

正如其他人所指出的,在空引用上调用扩展方法会导致此参数为空,并且没有其他特殊的事情会发生。 这提出了一个想法,使用扩展方法来编写保护条款。

你可以阅读这篇文章的例子: 如何减less环复杂性:警戒条款简短的版本是这样的:

 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); } } 

这是可以在空引用上调用的string类扩展方法:

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

该调用工作正常,只是因为运行时将成功调用null引用上的扩展方法。 那么你可以使用这个扩展方法来实现guard子句而不会有混乱的语法:

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

扩展方法是静态的,所以如果你不对这个MyObject做任何事情,这应该不是一个问题,快速testing应该validation它:)

当你想让自己可读和垂直的时候,没有什么黄金法则。

  • 一个值得从埃菲尔说,封装到一个方法的具体代码应该对付一些input,该代码是可行的,如果遇到一些先决条件,并确保预期的输出

在你的情况 – DesignByContract被打破了…你将要执行一些null实例的逻辑。