Nous discutons actuellement de la question de savoir si les méthodes d’extension dans .NET sont mauvaises ou non. Ou dans quelles circonstances les méthodes d’extension peuvent présenter des difficultés pour trouver des bogues ou se comporter de manière inattendue.
Nous sums venus avec:
Question:
Modifier:
Une autre situation très dangereuse. Supposons que vous ayez une méthode d’extension:
namespace Example.ExtensionMethods { public static class Extension { public static int Conflict(this TestMe obj) { return -1; } } }
Et utilisez-le:
namespace Example.ExtensionMethods.Conflict.Test { [TestFixture] public class ConflictExtensionTest { [Test] public void ConflictTest() { TestMe me = new TestMe(); int result = me.Conflict(); Assert.That(result, Is.EqualTo(-1)); } } }
Notez que l’espace de noms sur lequel vous l’utilisez est plus long.
Maintenant, vous référencez une dll avec ceci:
namespace Example.ExtensionMethods.Conflict { public static class ConflictExtension { public static int Conflict(this TestMe obj) { return 1; } } }
Et votre test échouera! Il va comstackr sans erreur de compilation. Il va simplement échouer . Sans même avoir à spécifier “using Example.ExtensionMethods.Conflict”. Le compilateur explorera le nom de l’espace de noms et trouvera Example.ExtensionMethods.Conflict.ConflictExtension avant Example.ExtensionMethods.Extension et l’utilisera sans jamais se plaindre de méthodes d’extension ambiguës . Oh l’horreur!
Quelques curiosités:
null
instances null
; cela peut être déroutant (mais parfois utile) ( edit ) Et bien sûr, il y a la Nullable
” Nullable
/ new()
” ( voir ici ) …
Je ne suis pas d’accord, le but des méthodes d’extension est d’append vos membres aux classes en boîte noire. Comme tout le rest, il y a des pièges, vous devez être attentif lors de la désignation, de la mise en œuvre et comprendre l’ordre hiérarchique des méthodes.
Une rupture que nous venons de trouver dans le projet MoreLINQ : si vous écrivez une méthode d’extension générique, il est impossible de vous assurer qu’elle fonctionnera avec tous les types. Nous avons une méthode avec cette signature:
public static IEnumerable Concat (this T head, IEnumerable tail)
Vous ne pouvez pas l’utiliser avec:
"foo".Concat(new [] { "tail" });
à cause de la méthode ssortingng.Concat
…
J’ai utilisé Ruby on Rails depuis presque aussi longtemps que j’ai utilisé C #. Ruby vous permet de faire quelque chose de similaire aux nouvelles méthodes d’extension. Il y a bien sûr des problèmes potentiels si quelqu’un appelle la méthode de la même manière, mais les avantages de pouvoir append des méthodes à une classe fermée l’emportent largement sur le désavantage potentiel (qui serait probablement causé par une mauvaise conception ou une mauvaise planification).
Pour vous assurer que les méthodes d’extension ne sont pas en conflit avec d’autres méthodes (extension ou autre), vous pouvez utiliser FxCop avec des règles telles que Empêcher les signatures de méthode d’extension dupliquées .
Tout d’abord, je pense que votre libellé est un peu trompeur. Je suppose que vous parlez de “types” et non d ‘”objects”.
Deuxièmement, le gros avantage des méthodes d’extension est que vous pouvez append des fonctionnalités à des types que vous ne contrôlez pas. Si vous contrôlez le type, pourquoi ne pas simplement modifier le type au lieu de recourir à des méthodes d’extension?
Dans mon équipe, nous avons adopté l’attitude selon laquelle les méthodes d’extension sont si utiles que vous ne pouvez pas les interdire de manière réaliste, mais si dangereuses (principalement en raison du problème de la dissimulation) qu’il faut être un peu prudent. Nous avons donc décidé que tous les noms de méthodes d’extension devaient être précédés de X
(nous avons donc un tas de XInit...()
pour initialiser les contrôles de manière utile, par exemple). De cette façon, a) la probabilité d’une collision de nommage est réduite et b) le programmeur sait qu’il utilise une méthode d’extension et non une méthode de classe.
Ce que les méthodes d’extension .Net sont aussi une forme limitée de MonkeyPatching (essayez d’ignorer le php rant qui s’y trouve).
Cela devrait vous donner de la matière pour votre discussion.