En C #, ¿qué sucede cuando llamas a un método de extensión en un objeto nulo?

¿El método se llama con un valor nulo o da una excepción de referencia nula?

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

Si este es el caso, nunca necesitaré verificar mi parámetro ‘this’ para null?

Eso funcionará bien (sin excepción). Los métodos de extensión no usan llamadas virtuales (es decir, usa la instrucción “call” il, no “callvirt”) por lo que no hay verificación nula a menos que usted mismo la escriba en el método de extensión. Esto es realmente útil en algunos casos:

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

etc

Fundamentalmente, las llamadas a llamadas estáticas son muy literales, es decir,

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

se convierte en:

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

donde obviamente no hay un cheque nulo.

Además de la respuesta correcta de Marc Gravell.

Puede obtener una advertencia del comstackdor si es obvio que el argumento es nulo:

 default(string).MyExtension(); 

Funciona bien en tiempo de ejecución, pero produce la advertencia "Expression will always cause a System.NullReferenceException, because the default value of string is null" .

Como ya ha descubierto, dado que los métodos de extensión son simplemente métodos estáticos glorificados, se null con referencias null pasadas, sin que se NullReferenceException una NullReferenceException . Pero, dado que se ven como métodos de instancia para la persona que llama, también deberían comportarse como tales. En ese caso, la mayoría de las veces debe verificar el parámetro y lanzar una excepción si es null . Está bien no hacer esto si el método se ocupa explícitamente de valores null y su nombre lo indica debidamente, como en los ejemplos a continuación:

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

También escribí una publicación en un blog sobre esto hace algún tiempo.

Un nulo se pasará al método de extensión.

Si el método intenta acceder al objeto sin verificar si es nulo, entonces sí, arrojará una excepción.

Un tipo aquí escribió los métodos de extensión “IsNull” e “IsNotNull” que verifican que la referencia pasó nulo o no. Personalmente creo que esto es una aberración y no debería haber visto la luz del día, pero es perfectamente válido c #.

Como otros señalaron, llamar a un método de extensión con referencia nula hace que este argumento sea nulo y no ocurra nada más especial. Esto da lugar a una idea de usar métodos de extensión para escribir cláusulas de guardia.

Puede leer este artículo para ver ejemplos: Cómo reducir la complejidad ciclomática: cláusula de guardia La versión corta es esta:

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

Este es el método de extensión de clase de cadena que se puede invocar en referencia nula:

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

La llamada funciona bien solo porque el tiempo de ejecución llamará con éxito al método de extensión en referencia nula. Luego puede usar este método de extensión para implementar cláusulas de protección sin syntax desordenada:

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

El método de extensión es estático, así que si no le haces nada a este MyObject, no debería ser un problema, una prueba rápida debería verificarlo 🙂

Hay pocas reglas de oro cuando quiere que sean legibles y verticales.

  • Vale la pena mencionar que Eiffel dice que el código específico encapsulado en un método debería funcionar en contra de alguna entrada, ese código es viable si se cumplen algunas condiciones previas y aseguran un resultado esperado.

En su caso, DesignByContract está roto … va a realizar un poco de lógica en una instancia nula.