J'ai une interface IFoo avec une méthode Bar, prenant un argument string. Cette interface a une implémentation qui renvoie une valeur constante, sans utiliser l'argument du tout. L'autre utilise les paramètres.
Comment éviter ce paramètre inutile? Voici une implémentation factice
public interface IFoo { string Bar(string parameter); } public class Foo : IFoo { public string Bar(string parameter) { return string.Format("{0}Fooooooo", parameter); } } public class ConstantFoo : IFoo { public string Bar(string parameter) { return "Baaaaaaar"; } } public class Caller { private readonly IFoo _foo; private readonly IFoo _constFoo; public Caller() { _foo = new Foo(); _constFoo = new ConstantFoo(); } public void DummyUsage() { string arg = "Wololo"; Console.WriteLine(_foo.Bar(arg)); Console.WriteLine(_constFoo.Bar(arg)); } }
3 Réponses :
La signature d'une fonction ou d'une propriété qu'une classe implémente doit toujours être identique à l'interface respective. Si vous avez vous-même le contrôle de l'interface, vous pouvez modifier la signature à la fois dans l'interface et dans la classe d'implémentation.
public interface IFoo { string Bar(); } public class Foo : IFoo { public string Bar() { return "Fooooooo"; } }
Si ce n'est pas ce que vous voulez, cela peut suggérer que votre modèle d'héritage est pas très bien défini.
où vous avez perdu le paramètre
.. comment est défini?
Déclarez une méthode supplémentaire Bar () sans aucun paramètre dans l'interface IFoo
public interface IFoo { string Bar(string parameter); string Bar(); } public class Foo : IFoo { public string Bar(string parameter) { return string.Format("{0}Fooooooo", parameter); } public string Bar() { return string.Empty; } } public class ConstantFoo : IFoo { public string Bar(string parameter) { return string.Empty; } public string Bar() { return "Baaaaaaar"; } } public class Caller { private readonly IFoo _foo; private readonly IFoo _constFoo; public Caller() { _foo = new Foo(); _constFoo = new ConstantFoo(); } public void DummyUsage() { string arg = "Wololo"; Console.WriteLine(_foo.Bar(arg)); Console.WriteLine(_constFoo.Bar()); } }
Votre exemple compte avec un fait. En tant que producteur de classe, vous connaissez les détails de l'implémentation que vous savez exactement quel type d'instance est IFoo
public class Caller { private readonly IParametrizedFoo _parametrizedFoo; private readonly IFoo _foo; public Caller(IParametrizedFoo parametrizedFoo, IFoo foo) { _parametrizedFoo= parametrizedFoo; _foo= foo; } public void DummyUsage() { string arg = "Wololo"; Console.WriteLine(parametrizedFoo.Bar(arg)); Console.WriteLine(_foo.Bar()); }
Maintenant, pensez à propos de ceci:
public class Foo : IParametrizedFoo { public string Bar(string parameter) { return string.Format("{0}Fooooooo", parameter); } } public class ConstantFoo : IFoo, IParametrizedFoo { public string Bar() { return "Baaaaaaar"; } string IParametrizedFoo.Bar(string parameter) { Bar(); } }
Maintenant un autre
Imaginez que vous avez 2 interfaces:
interface IFoo { void Bar(); } interface IParametrizedFoo { void Bar(string parameter); }
alors vous pouvez avoir la mise en œuvre
public class Caller { private readonly IEnumerable<IFoo> _fooServices; public Caller(IEnumerable<IFoo> fooServices) { _fooServices = fooServices; } public void DummyUsage() { string arg = "Wololo"; foreach(IFoo fooService in _fooServices) { Console.WriteLine(fooService.Bar(arg)); //==> you do not know what type of foo it is if it require internally argument or not .. But you have to pass it to satisfy contract defined by IFoo interface } }
puis l'utilisation
public class Caller { private readonly IFoo _foo; private readonly IFoo _constFoo; public Caller() { _foo = new Foo(); // => here is exact instance type _constFoo = new ConstantFoo(); // => here is exact instance type } public void DummyUsage() { string arg = "Wololo"; Console.WriteLine(_foo.Bar(arg)); // -> here you know that you need parameterarg Console.WriteLine(_constFoo.Bar(arg)); // -> here you know that you do not need parameter arg }
Mais je ne pense toujours pas que ce soit le meilleur conception
Interface définissant le contrat. Vous n'êtes pas obligé d'utiliser ce paramètre. Un autre cas est par exemple les événements .. Imaginez que Microsoft vous fournisse des événements. Habituellement, la méthode du gestionnaire d'événements a 2 arguments
void MyHandler (expéditeur de l'objet, EventArgs e)
Une fois l'événement déclenché, ce hndler est appelé et 2 arguments sont utilisables dans la portée de la méthode. Vous pouvez les utiliser mais il n'y a pas de force pour vous forcer à les utiliser. La même chose que vous pouvez appliquer à l'interface (tierce partie) dans le cas où vous êtes producteur d'interface, peut-être que vous pouvez réfléchir à la façon de changer la conception de votre application.L'interface est un contrat. Lorsque vous avez une instance de
IFoo
, vous savez seulement qu'il aBar (string)
et vous ne savez pas si le paramètre est inutile ou non, vous devez le passer. Ce n'est pas grave si l'implémentation ne l'utilise pas, mais elle doit quand même suivre un contrat et définir ce paramètre comme signature de méthode. Vous pouvez lui donner un nom sophistiqué, par exemplenotUsed
et même donner une valeur par défaut facultative (ou utiliser une surcharge), alors si vous avez une instance deConstantFoo
, vous pouvez appelerBar ()
sans paramètreExemple de commentaire de Sinatr: dotnetfiddle.net/I9rrkD
@Fildor je pense que dans ce cas, les arguments optionnels ne sont pas une bonne idée
@PeterM. Je viens de compiler un exemple de ce que Sinatr a proposé à OP de voir.