Question Interface définissant une signature de constructeur?


Il est étrange que ce soit la première fois que je me heurte à ce problème, mais:

Comment définissez-vous un constructeur dans une interface C #?

modifier
Certaines personnes voulaient un exemple (c'est un projet de temps libre, alors oui, c'est un jeu)

IDrawable
 + Mise à jour
 + Draw

Pour être en mesure de mettre à jour (vérifier le bord de l'écran, etc) et dessiner lui-même, il aura toujours besoin d'un GraphicsDeviceManager. Je veux donc m'assurer que l'objet y est référencé. Cela appartiendrait au constructeur.

Maintenant que j'ai écrit cela, je pense que ce que je suis en train de mettre en œuvre ici est IObservable et le GraphicsDeviceManager devrait prendre la IDrawable... Il semble que je n'obtiens pas le framework XNA, ou que le framework n'est pas très bien pensé.

modifier
Il semble y avoir une certaine confusion dans ma définition du constructeur dans le contexte d’une interface. Une interface ne peut en effet pas être instanciée et n'a donc pas besoin d'un constructeur. Ce que je voulais définir était une signature pour un constructeur. Exactement comme une interface peut définir une signature d'une certaine méthode, l'interface pourrait définir la signature d'un constructeur.


452
2018-03-06 18:13


origine


Réponses:


Comme déjà noté, vous ne pouvez pas avoir de constructeurs sur une interface. Mais comme il s’agit d’un résultat si haut classé sur Google environ 7 ans plus tard, j’ai pensé que je mettrais tout en œuvre pour vous montrer comment utiliser une classe de base abstraite en tandem avec votre interface existante et réduire la quantité de refactoring. nécessaire dans le futur pour des situations similaires. Ce concept a déjà été évoqué dans certains commentaires, mais je pensais qu'il serait utile de montrer comment le faire.

Vous avez donc votre interface principale qui ressemble à ceci:

public interface IDrawable
{
    void Update();
    void Draw();
}

Créez maintenant une classe abstraite avec le constructeur que vous souhaitez appliquer. En fait, comme il est maintenant disponible depuis le moment où vous avez écrit votre question originale, nous pouvons avoir un peu de fantaisie et utiliser des génériques dans cette situation afin de pouvoir l'adapter à d'autres interfaces qui pourraient nécessiter les mêmes fonctionnalités mais avec des constructeurs différents:

public abstract class MustInitialize<T>
{
    public MustInitialize(T parameters)
    {

    }
}

Vous devez maintenant créer une nouvelle classe héritant à la fois de l'interface IDrawable et de la classe abstraite MustInitialize:

public class Drawable : MustInitialize<GraphicsDeviceManager>, IDrawable
{
    GraphicsDeviceManager _graphicsDeviceManager;

    public Drawable(GraphicsDeviceManager graphicsDeviceManager)
        : base (graphicsDeviceManager)
    {
        _graphicsDeviceManager = graphicsDeviceManager;
    }

    public void Update()
    {
        //use _graphicsDeviceManager here to do whatever
    }

    public void Draw()
    {
        //use _graphicsDeviceManager here to do whatever
    }
}

Ensuite, créez simplement une instance de Drawable et vous êtes prêt à partir:

IDrawable drawableService = new Drawable(myGraphicsDeviceManager);

La chose intéressante ici est que la nouvelle classe Drawable que nous avons créée se comporte toujours comme ce que nous attendrions d'un IDrawable.

Si vous devez transmettre plusieurs paramètres au constructeur MustInitialize, vous pouvez créer une classe définissant les propriétés de tous les champs que vous devez transmettre.


77
2018-01-16 21:57



Tu ne peux pas. C'est parfois une douleur, mais vous ne seriez pas capable de l'appeler en utilisant des techniques normales de toute façon.

Dans un article de blog que j'ai suggéré interfaces statiques qui ne serait utilisable que dans des contraintes de type générique - mais pourrait être très pratique, IMO.

Un point à propos de si vous pourrait définir un constructeur dans une interface, vous auriez du mal à dériver des classes:

public class Foo : IParameterlessConstructor
{
    public Foo() // As per the interface
    {
    }
}

public class Bar : Foo
{
    // Yikes! We now don't have a parameterless constructor...
    public Bar(int x)
    {
    }
}

295
2018-03-06 18:14



Une contribution très tardive démontrant un autre problème avec les constructeurs interfacés. (Je choisis cette question parce qu'elle a l'articulation la plus claire du problème). Supposons que nous puissions avoir:

interface IPerson
{
    IPerson(string name);
}

interface ICustomer
{
    ICustomer(DateTime registrationDate);
}

class Person : IPerson, ICustomer
{
    Person(string name) { }
    Person(DateTime registrationDate) { }
}

Où, par convention, l'implémentation du "constructeur d'interface" est remplacée par le nom du type.

Maintenant, faites une instance:

ICustomer a = new Person("Ernie");

Dirions-nous que le contrat ICustomer est obéi?

Et qu'en est-il de cela:

interface ICustomer
{
    ICustomer(string address);
}

128
2017-11-11 18:33



Tu ne peux pas.

Les interfaces définissent les contrats que d'autres objets implémentent et n'ont donc pas d'état à initialiser.

Si vous avez un état à initialiser, vous devriez plutôt envisager d'utiliser une classe de base abstraite.


55
2018-03-06 18:15



Il n'est pas possible de créer une interface qui définit les constructeurs, mais est possible de définir une interface qui oblige un type à avoir un constructeur sans paramétrer, bien que ce soit une syntaxe très laide qui utilise des génériques ... Je ne suis pas vraiment sûr que ce soit vraiment un bon modèle de codage.

public interface IFoo<T> where T : new()
{
  void SomeMethod();
}

public class Foo : IFoo<Foo>
{
  // This will not compile
  public Foo(int x)
  {

  }

  #region ITest<Test> Members

  public void SomeMethod()
  {
    throw new NotImplementedException();
  }

  #endregion
}

D'un autre côté, si vous voulez tester si un type a un constructeur paramerterless, vous pouvez le faire en utilisant la réflexion:

public static class TypeHelper
{
  public static bool HasParameterlessConstructor(Object o)
  {
    return HasParameterlessConstructor(o.GetType());
  }

  public static bool HasParameterlessConstructor(Type t)
  {
    // Usage: HasParameterlessConstructor(typeof(SomeType))
    return t.GetConstructor(new Type[0]) != null;
  }
}

J'espère que cela t'aides.


19
2018-03-06 18:40



Je me suis penché sur cette question et je me suis dit, peut-être que nous abordons ce problème dans le mauvais sens. Les interfaces peuvent ne pas être le chemin à parcourir quand il s'agit de définir un constructeur avec certains paramètres ... mais une classe de base (abstraite) l'est.

Si vous créez une classe de base avec un constructeur qui accepte les paramètres dont vous avez besoin, chaque classe qui en découle doit les fournir.

public abstract class Foo
{
  protected Foo(SomeParameter x)
  {
    this.X = x;
  }

  public SomeParameter X { get; private set }
}

public class Bar : Foo // Bar inherits from Foo
{
  public Bar() 
    : base(new SomeParameter("etc...")) // Bar will need to supply the constructor param
  {
  }
}

19
2018-03-02 18:35



L'approche générique de l'usine semble toujours idéale. Vous savez que l'usine a besoin d'un paramètre, et il arrive que ces paramètres soient transmis au constructeur de l'objet instancié.

Notez, ceci est juste pseudo code vérifié par la syntaxe, il peut y avoir un avertissement d'exécution que je manque ici:

public interface IDrawableFactory
{
    TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager) 
              where TDrawable: class, IDrawable, new();
}

public class DrawableFactory : IDrawableFactory
{
    public TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager) 
                     where TDrawable : class, IDrawable, new()
    {
        return (TDrawable) Activator
                .CreateInstance(typeof(TDrawable), 
                                graphicsDeviceManager);
    }

}

public class Draw : IDrawable
{
 //stub
}

public class Update : IDrawable {
    private readonly GraphicsDeviceManager _graphicsDeviceManager;

    public Update() { throw new NotImplementedException(); }

    public Update(GraphicsDeviceManager graphicsDeviceManager)
    {
        _graphicsDeviceManager = graphicsDeviceManager;
    }
}

public interface IDrawable
{
    //stub
}
public class GraphicsDeviceManager
{
    //stub
}

Un exemple d'utilisation possible:

    public void DoSomething()
    {
        var myUpdateObject = GetDrawingObject<Update>(new GraphicsDeviceManager());
        var myDrawObject = GetDrawingObject<Draw>(null);
    }

Accordé, vous voudriez seulement les instances de créer par l'usine pour garantir que vous avez toujours un objet initialisé de manière appropriée. Peut-être en utilisant un cadre d'injection de dépendance comme AutoFac aurait du sens Update () pourrait "demander" le conteneur IoC pour un nouvel objet GraphicsDeviceManager.


5
2018-06-28 21:17