Interface que define uma assinatura de construtor?

É estranho que esta seja a primeira vez que me deparo com este problema, mas:

Como você define um construtor em uma interface c #?

Editar
Algumas pessoas queriam um exemplo (é um projeto de tempo livre, então sim, é um jogo)

Idenável
+ Atualização
+ Desenhar

Para poder atualizar (verificar a borda da canvas etc) e desenhar a si mesmo, ele sempre precisará de um GraphicsDeviceManager . Então, quero ter certeza de que o object tenha uma referência a ele. Isso pertence ao construtor.

Agora que escrevi isso, acho que o que estou implementando aqui é IObservable e o GraphicsDeviceManager deve pegar o IDrawable … Parece que não recebo o framework XNA, ou o framework não é muito bem pensado.

Editar
Parece haver alguma confusão sobre minha definição de construtor no contexto de uma interface. Uma interface de fato não pode ser instanciada, portanto, não precisa de um construtor. O que eu queria definir era uma assinatura para um construtor. Exatamente como uma interface pode definir uma assinatura de um determinado método, a interface poderia definir a assinatura de um construtor.

Como já foi bem notado, você não pode ter construtores em uma interface. Mas como esse é um resultado muito bem classificado no Google sete anos depois, pensei em include aqui – especificamente para mostrar como você poderia usar uma class base abstrata em conjunto com sua interface existente e talvez reduzir a quantidade de refatoração necessário no futuro para situações semelhantes. Esse conceito já foi sugerido em alguns dos comentários, mas achei que valeria a pena mostrar como realmente fazer isso.

Então você tem sua interface principal que parece até agora:

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

Agora crie uma class abstrata com o construtor que você quer impor. Na verdade, como agora está disponível desde o momento em que você escreveu sua pergunta original, podemos usar um pouco de genérico nessa situação para podermos adaptar isso a outras interfaces que possam precisar da mesma funcionalidade, mas que tenham diferentes requisitos de construtor:

 public abstract class MustInitialize { public MustInitialize(T parameters) { } } 

Agora você precisará criar uma nova class que herda da interface IDrawable e da class abstrata MustInitialize:

 public class Drawable : MustInitialize, 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 } } 

Em seguida, basta criar uma instância de Drawable e você é bom para ir:

 IDrawable drawableService = new Drawable(myGraphicsDeviceManager); 

O legal aqui é que a nova class Drawable que criamos ainda se comporta como o que seria de esperar de um IDrawable.

Se você precisar passar mais de um parâmetro para o construtor MustInitialize, poderá criar uma class que defina propriedades para todos os campos que você precisará passar.

Você não pode. É ocasionalmente uma dor, mas você não seria capaz de chamar isso usando técnicas normais.

Em um post de blog, eu sugeri interfaces estáticas que seriam utilizáveis ​​somente em restrições de tipo genérico – mas poderiam ser realmente úteis, IMO.

Um ponto sobre se você poderia definir um construtor dentro de uma interface, você teria problemas para derivar classs:

 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) { } } 

Uma contribuição muito tardia, demonstrando outro problema com os construtores interfaceados. (Eu escolho esta pergunta porque tem a articulação mais clara do problema). Suponha que poderíamos ter:

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

Onde por convenção a implementação do “construtor de interface” é substituída pelo nome do tipo.

Agora faça uma instância:

 ICustomer a = new Person("Ernie"); 

Nós diríamos que o contrato ICustomer é obedecido?

E sobre isso:

 interface ICustomer { ICustomer(string address); } 

Você não pode.

As interfaces definem contratos que outros objects implementam e, portanto, não possuem nenhum estado que precise ser inicializado.

Se você tiver algum estado que precise ser inicializado, considere a possibilidade de usar uma class base abstrata.

Não é possível criar uma interface que defina construtores, mas é possível definir uma interface que force um tipo a ter um construtor sem parâmetros, embora seja uma syntax muito feia que usa genéricos … Na verdade, não tenho tanta certeza de que é realmente um bom padrão de codificação.

 public interface IFoo where T : new() { void SomeMethod(); } public class Foo : IFoo { // This will not compile public Foo(int x) { } #region ITest Members public void SomeMethod() { throw new NotImplementedException(); } #endregion } 

Por outro lado, se você quiser testar se um tipo tem um construtor sem parâmetros, você pode fazer isso usando reflection:

 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; } } 

Espero que isto ajude.

Eu estava olhando para essa questão e pensei comigo mesmo, talvez estejamos abordando esse problema da maneira errada. Interfaces podem não ser o caminho a seguir quando se trata de definir um construtor com certos parâmetros … mas uma class base (abstrata) é.

Se você criar uma class base com um construtor que aceite os parâmetros necessários, cada class que derive dela precisará fornecê-los.

 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 { } } 

A abordagem genérica de fábrica ainda parece ideal. Você saberia que a fábrica requer um parâmetro, e isso só aconteceria se esses parâmetros fossem passados ​​para o construtor do object sendo instanciado.

Note, isso é apenas um pseudo código verificado na syntax, pode haver uma advertência em tempo de execução que estou perdendo aqui:

 public interface IDrawableFactory { TDrawable GetDrawingObject(GraphicsDeviceManager graphicsDeviceManager) where TDrawable: class, IDrawable, new(); } public class DrawableFactory : IDrawableFactory { public TDrawable GetDrawingObject(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 } 

Um exemplo de uso possível:

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

Concedido, você só quereria criar as instâncias através da fábrica para garantir que você sempre tenha um object apropriadamente inicializado. Talvez usar um framework de injeção de dependência como o AutoFac faria sentido; Update () poderia “pedir” o contêiner IoC para um novo object GraphicsDeviceManager.

Uma maneira de resolver este problema que encontrei é separar a construção em uma fábrica separada. Por exemplo, eu tenho uma class abstrata chamada IQueueItem e preciso de uma maneira de traduzir esse object para e de outro object (CloudQueueMessage). Então, na interface IQueueItem eu tenho –

 public interface IQueueItem { CloudQueueMessage ToMessage(); } 

Agora, também preciso de uma maneira de minha class de fila real traduzir uma CloudQueueMessage de volta para um IQueueItem – ou seja, a necessidade de uma construção estática como IQueueItem objMessage = ItemType.FromMessage. Em vez disso, defini outra interface IQueueFactory –

 public interface IQueueItemFactory where T : IQueueItem { T FromMessage(CloudQueueMessage objMessage); } 

Agora posso finalmente escrever minha class de fila genérica sem a restrição new (), que no meu caso foi o principal problema.

 public class AzureQueue where T : IQueueItem { private IQueueItemFactory _objFactory; public AzureQueue(IQueueItemFactory objItemFactory) { _objFactory = objItemFactory; } public T GetNextItem(TimeSpan tsLease) { CloudQueueMessage objQueueMessage = _objQueue.GetMessage(tsLease); T objItem = _objFactory.FromMessage(objQueueMessage); return objItem; } } 

agora posso criar uma instância que satisfaça os critérios para mim

  AzureQueue objJobQueue = new JobQueue(new JobItemFactory()) 

Espero que isso ajude alguém a sair algum dia, obviamente, muito código interno removido para tentar mostrar o problema e a solução

Uma maneira de resolver esse problema é aproveitar os genéricos e a restrição new ().

Em vez de expressar seu construtor como um método / function, você pode expressá-lo como uma class / interface de fábrica. Se você especificar a restrição genérica new () em cada site de chamada que precisar criar um object da sua class, poderá transmitir os argumentos do construtor de acordo.

Para o seu exemplo IDrawable:

 public interface IDrawable { void Update(); void Draw(); } public interface IDrawableConstructor where T : IDrawable { T Construct(GraphicsDeviceManager manager); } public class Triangle : IDrawable { public GraphicsDeviceManager Manager { get; set; } public void Draw() { ... } public void Update() { ... } public Triangle(GraphicsDeviceManager manager) { Manager = manager; } } public TriangleConstructor : IDrawableConstructor { public Triangle Construct(GraphicsDeviceManager manager) { return new Triangle(manager); } } 

Agora, quando você usa:

 public void SomeMethod(GraphicsDeviceManager manager) where TBuilder: IDrawableConstructor, new() { // If we need to create a triangle Triangle triangle = new TBuilder().Construct(manager); // Do whatever with triangle } 

Você pode até mesmo concentrar todos os methods de criação em uma única class usando a implementação explícita da interface:

 public DrawableConstructor : IDrawableConstructor, IDrawableConstructor, IDrawableConstructor { Triangle IDrawableConstructor.Construct(GraphicsDeviceManager manager) { return new Triangle(manager); } Square IDrawableConstructor.Construct(GraphicsDeviceManager manager) { return new Square(manager); } Circle IDrawableConstructor.Construct(GraphicsDeviceManager manager) { return new Circle(manager); } } 

Para usá-lo:

 public void SomeMethod(GraphicsDeviceManager manager) where TBuilder: IDrawableConstructor, new() { // If we need to create an arbitrary shape TShape shape = new TBuilder().Construct(manager); // Do whatever with the shape } 

Outra maneira é usando expressões lambda como inicializadores. Em algum momento no início da hierarquia de chamadas, você saberá quais objects precisará instanciar (ou seja, quando estiver criando ou obtendo uma referência ao seu object GraphicsDeviceManager). Assim que você tiver, passe o lambda

 () => new Triangle(manager) 

aos methods subsequentes, para que eles saibam como criar um Triângulo a partir de então. Se você não puder determinar todos os methods possíveis, você sempre poderá criar um dictionary de tipos que implementem IDrawable usando reflection e registre a expressão lambda mostrada acima em um dictionary que você pode armazenar em um local compartilhado ou passar para outras chamadas de function.

Você poderia fazer isso com o truque dos genéricos, mas ainda é vulnerável ao que Jon Skeet escreveu:

 public interface IHasDefaultConstructor where T : IHasDefaultConstructor, new() { } 

A class que implementa essa interface deve ter um construtor sem parâmetros:

 public class A : IHasDefaultConstructor //Notice A as generic parameter { public A(int a) { } //compile time error } 

você não sabe.

o construtor faz parte da class que pode implementar uma interface. A interface é apenas um contrato de methods que a class deve implementar.

Seria muito útil se fosse possível definir construtores em interfaces.

Dado que uma interface é um contrato que deve ser usado da maneira especificada. A abordagem a seguir pode ser uma alternativa viável para alguns cenários:

 public interface IFoo { ///  /// Initialize foo. ///  ///  /// Classes that implement this interface must invoke this method from /// each of their constructors. ///  ///  /// Thrown when instance has already been initialized. ///  void Initialize(int a); } public class ConcreteFoo : IFoo { private bool _init = false; public int b; // Obviously in this case a default value could be used for the // constructor argument; using overloads for purpose of example public ConcreteFoo() { Initialize(42); } public ConcreteFoo(int a) { Initialize(a); } public void Initialize(int a) { if (_init) throw new InvalidOperationException(); _init = true; b = a; } } 

Uma maneira de forçar algum tipo de construtor é declarar apenas Getters na interface, o que poderia significar que a class de implementação deve ter um método, idealmente um construtor, para ter o valor definido ( private ) para ele.

Embora você não possa definir uma assinatura de construtor em uma interface, acho que vale a pena mencionar que isso pode ser um ponto a considerar para uma class abstrata. As classs abstratas podem definir assinaturas de método não implementadas (abstratas) da mesma maneira que uma interface, mas também podem ter implementado methods e construtores (concretos).

A desvantagem é que, por ser um tipo de class, não pode ser usado para nenhum dos vários cenários de tipo de inheritance que uma interface pode ter.

O propósito de uma interface é impor uma certa assinatura de object. Ele explicitamente não deve se preocupar com o funcionamento de um object internamente. Portanto, um construtor em uma interface não faz sentido do ponto de vista conceitual.

Existem algumas alternativas:

  • Crie uma class abstrata que atue como uma implementação padrão mínima. Essa class deve ter os construtores que você espera que as classs de implementação tenham.

  • Se você não se importa com o exagero, use o padrão AbstractFactory e declare um método na interface da class de fábrica que tenha as assinaturas necessárias.

  • Passe o GraphicsDeviceManager como um parâmetro para os methods Update e Draw .

  • Use uma estrutura de Programação Orientada a Objetos Composicionais para passar o GraphicsDeviceManager para a parte do object que o requer. Esta é uma solução bastante experimental na minha opinião.

A situação que você descreve não é fácil de lidar em geral. Um caso semelhante seria entidades em um aplicativo de negócios que exigem access ao database.

Se eu entendi OP corretamente, queremos impor um contrato onde GraphicsDeviceManager é sempre inicializado pela implementação de classs. Eu tive um problema semelhante e estava procurando uma solução melhor, mas é o melhor que consigo pensar:

Adicione um SetGraphicsDeviceManager (GraphicsDeviceManager gdo) à interface e, dessa forma, as classs de implementação serão forçadas a escrever uma lógica que exigirá uma chamada do construtor.