La méthode est-elle appelée avec une valeur null ou donne-t-elle une exception de référence null?
MyObject myObject = null;
myObject.MyExtensionMethod(); // <-- is this a null reference exception?
Si tel est le cas, je n'aurai jamais besoin de vérifier mon paramètre 'this' pour null?
Cela fonctionnera bien (sans exception). Les méthodes d’extension n’utilisent pas d’appels virtuels (c’est-à-dire qu’elles utilisent l’instruction "call", pas "callvirt"). Par conséquent, il n’ya pas de vérification de null à moins que vous ne l’écriviez vous-même dans la méthode d’extension. Ceci est utile dans quelques cas:
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);
}
etc
Fondamentalement, les appels à des appels statiques sont très littéraux - c.-à-d.
string s = ...
if(s.IsNullOrEmpty()) {...}
devient:
string s = ...
if(YourExtensionClass.IsNullOrEmpty(s)) {...}
où il n'y a évidemment pas de chèque nul.
Ajout à la réponse correcte de Marc Gravell.
Vous pouvez recevoir un avertissement du compilateur s'il est évident que l'argument this est null:
default(string).MyExtension();
Fonctionne bien au moment de l'exécution, mais produit l'avertissement "Expression will always cause a System.NullReferenceException, because the default value of string is null"
.
Comme vous l'avez déjà découvert, étant donné que les méthodes d'extension sont simplement des méthodes statiques glorifiées, elles seront appelées avec les références null
passées, sans qu'un jeton NullReferenceException
ne soit jeté. Mais, puisqu'elles ressemblent à des méthodes d'instance pour l'appelant, elles devraient également se comporter En tant que tel. La plupart du temps, vous devriez alors vérifier le paramètre this
et émettre une exception s’il s’agit de null
. C'est bien de ne pas le faire si la méthode s'occupe explicitement de null
valeurs et que son nom l'indique correctement, comme dans les exemples ci-dessous:
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;
}
}
J'ai aussi écrit n article de blog à ce sujet il y a quelque temps.
Un null sera passé à la méthode d'extension.
Si la méthode tente d'accéder à l'objet sans la vérifier si elle est nulle, alors oui, elle lève une exception.
Un gars ici a écrit les méthodes d'extension "IsNull" et "IsNotNull" qui vérifient si la référence est null ou non. Personnellement, je pense que c'est une aberration et que je n'aurais pas dû voir la lumière du jour, mais c'est parfaitement valide c #.
Comme d'autres l'ont fait remarquer, l'appel d'une méthode d'extension sur une référence null entraîne la nullité de cet argument et que rien d'autre ne se produira. Cela donne à penser à utiliser des méthodes d'extension pour écrire des clauses de protection.
Vous pouvez lire cet article pour des exemples: Comment réduire la complexité cyclomatic: clause de garde La version courte est la suivante:
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);
}
}
C'est la méthode d'extension de la classe string qui peut être appelée sur une référence null:
((string)null).AssertNonEmpty("null");
L'appel fonctionne correctement uniquement parce que l'exécution appelle correctement la méthode d'extension sur une référence null. Ensuite, vous pouvez utiliser cette méthode d'extension pour implémenter des clauses de garde sans syntaxe désordonnée:
public IRegisteredUser RegisterUser(string userName, string referrerName)
{
userName.AssertNonEmpty("userName");
referrerName.AssertNonEmpty("referrerName");
...
}
La méthode d'extension est statique, donc si vous ne faites rien à ce MyObject, cela ne devrait pas être un problème, un test rapide devrait le vérifier :)