Pourquoi utiliser l’implémentation d’interface explicite pour appeler une méthode protégée?

Lors de la navigation dans le code source ASP.NET MVC dans codeplex , j’ai constaté qu’il est courant d’avoir une classe implémentant explicitement l’interface. La méthode / propriété implémentée explicitement appelle ensuite une autre méthode / propriété “virtual protected” portant le même nom.

Par exemple,

public class MvcHandler : IHttpHandler, IRequiresSessionState { protected virtual bool IsReusable { get { return false; } } bool IHttpHandler.IsReusable { get { return IsReusable; } } } 

Je suis maintenant sûr des avantages de ce type de programmation. Pour moi, je préfère implémenter implicitement l’interface IHttpHandler.

Je suppose que l’auteur ne veut tout simplement pas que MvcHandler ait une propriété publique IsResuable . La propriété IsReusable ne peut être utilisée que lorsque l’instance de MvcHandler est traitée comme un IHttpHandler . Pourtant, je ne suis pas sûr de savoir pourquoi l’auteur agit de cette façon.

Quelqu’un sait plus d’avantages sur ce style d’implémentation d’interface?

Eh bien, ce n’est pas spécifique à MVC, mais cette approche vous permet de garder l’API publique centrale propre . C’est également utile s’il existe un risque que différentes interfaces / etc. aient le même nom et la même signature, mais une signification différente. En réalité, c’est rare.

Il vous permet également de fournir une implémentation dans laquelle vous souhaitez que le type de retour change dans les sous-classes:

( ICloneable choisi pour la simplicité – ne vous attardez pas sur le fait qu’il s’agit d’une interface mal définie … un meilleur exemple aurait été des choses comme DbCommand etc., qui le font – mais c’est plus difficile à montrer dans un court exemple. )

 class Foo : ICloneable { public Foo Clone() { return CloneCore(); } object ICloneable.Clone() { return CloneCore(); } protected virtual Foo CloneCore() { ... } } class Bar : Foo { protected override Foo CloneCore() { ... } public new Bar Clone() { return (Bar)CloneCore(); } } 

Si nous avions utilisé une méthode virtuelle publique, nous ne pourrions pas la override et utiliser new dans la classe de base, car vous n’êtes pas autorisé à faire les deux:

 class A { public virtual A SomeMethod() { ... } } class B : A { public override A SomeMethod() { ... } //Error 1 Type 'B' already defines a member called 'SomeMethod' with the same parameter types public new B SomeMethod() { ... } } 

En utilisant l’approche virtuelle protégée, toute utilisation:

  • Foo.Clone ()
  • Bar.Clone ()
  • Clonable.Clone ()

Tous utilisent la bonne CloneCore() pour le type concret.

Si une classe implémente explicitement IFoo.Bar et qu’une classe dérivée a besoin de IFoo.Bar pour faire quelque chose de différent, la classe dérivée n’aura aucun moyen d’appeler l’implémentation de classe de base de cette méthode. Une classe dérivée qui ne ré-implémente pas IFoo.Bar pourrait appeler l’implémentation de la classe de base via ((IFoo)this).Bar() , mais si la classe dérivée IFoo.Bar (comme il le faudrait dans l’ordre pour changer de comportement), l’appel susmentionné irait à la ré-implémentation de la classe dérivée, plutôt qu’à la mise en œuvre de la classe de base. Même ((IFoo)(BaseType)this).bar pas, car la ((IFoo)(BaseType)this).bar une référence vers un type d’interface ignorera toute information sur le type de la référence (par opposition au type de l’instance) qui a été convertie.

Avoir une implémentation d’interface explicite ne fait rien mais appeler une méthode protégée évite ce problème, car une classe dérivée peut changer le comportement de la méthode d’interface en redéfinissant la méthode virtuelle, tout en conservant la possibilité d’appeler l’implémentation de base comme bon lui semble. IMHO, C # aurait dû faire en sorte qu’une implémentation d’interface explicite produise une méthode virtuelle avec un nom conforme à CLS. Ainsi, une personne écrivant en C # un dérivé d’une classe ayant explicitement implémenté IFoo.Bar pourrait override void IFoo.Bar , et quelqu’un écrivant dans d’autres langues pourraient indiquer, par exemple, Overrides Sub Explicit_IFoo_Bar() ; comme n’importe quelle classe dérivée peut IFoo.Bar , et comme toute classe dérivée qui ne IFoo.Bar pas IFoo.Bar peut l’appeler elle-même, je ne vois pas d’objective utile pour que l’implémentation explicite soit scellée. .

Incidemment, dans vb.net, le modèle normal serait simplement Protected Overridable Sub IFoo_Bar() Implements IFoo.Bar , sans nécessiter de méthode virtuelle distincte.

  1. Lorsqu’un membre est explicitement implémenté, il est impossible d’y accéder via une instance de classe, mais uniquement via une instance de l’interface. reference: Didacticiel d’implémentation d’interface explicite
  2. Selon mon expérience, si l’implémenteur d’interface implémente explicitement une interface, il recevra une erreur du compilateur après que vous ayez supprimé une méthode de l’interface, mais il ne le notifiera pas s’il l’implémente implicitement et la méthode restra dans le code.

échantillon pour la raison 1:

 public interface IFoo { void method1(); void method2(); } public class Foo : IFoo { // you can't declare explicit implemented method as public void IFoo.method1() { } public void method2() { } private void test() { var foo = new Foo(); foo.method1(); //ERROR: not accessible because foo is object instance method1(); //ERROR: not accessible because foo is object instance foo.method2(); //OK method2(); //OK IFoo ifoo = new Foo(); ifoo.method1(); //OK, because ifoo declared as interface ifoo.method2(); //OK } }