c# Interfaccia che definisce una firma del costruttore?





8 Answers

Non puoi Occasionalmente è un dolore, ma non si potrebbe comunque chiamarlo usando le normali tecniche.

In un post del blog ho suggerito interfacce statiche che sarebbero utilizzabili solo in vincoli di tipo generico, ma potrebbero essere davvero a portata di mano, IMO.

Un punto su se potessi definire un costruttore all'interno di un'interfaccia, avresti problemi nel derivare le classi:

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)
    {
    }
}
c# interface constructor

È strano che questa sia la prima volta che mi imbatto in questo problema, ma:

Come si definisce un costruttore in un'interfaccia C #?

modificare
Alcune persone volevano un esempio (è un progetto a tempo libero, quindi sì, è un gioco)

IDrawable
+ Aggiornamento
+ Draw

Per essere in grado di effettuare l'aggiornamento (controllare il bordo dello schermo ecc.) E disegnare da solo, sarà sempre necessario un GraphicsDeviceManager . Quindi voglio assicurarmi che l'oggetto abbia un riferimento ad esso. Questo dovrebbe appartenere al costruttore.

Ora che ho scritto questo, penso che quello che sto implementando qui è IObservable e il GraphicsDeviceManager dovrebbe prendere l' IDrawable ... Sembra che non ottengo il framework XNA, o il framework non è pensato molto bene.

modificare
Sembra esserci una certa confusione circa la mia definizione di costruttore nel contesto di un'interfaccia. Un'interfaccia non può essere istanziata quindi non ha bisogno di un costruttore. Quello che volevo definire era una firma per un costruttore. Esattamente come un'interfaccia può definire una firma di un determinato metodo, l'interfaccia potrebbe definire la firma di un costruttore.




Non puoi

Le interfacce definiscono i contratti implementati da altri oggetti e quindi non hanno uno stato che deve essere inizializzato.

Se hai uno stato che deve essere inizializzato, dovresti prendere in considerazione l'utilizzo di una classe base astratta.




Stavo guardando indietro a questa domanda e ho pensato a me stesso, forse stiamo attaccando questo problema nel modo sbagliato. Le interfacce potrebbero non essere la strada da percorrere quando si tratta di definire un costruttore con determinati parametri ... ma una classe base (astratta) lo è.

Se crei una classe base con un costruttore lì che accetta i parametri necessari, ogni classe che ne designa deve fornirli.

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



Un modo per risolvere questo problema che ho trovato è quello di separare la costruzione in una fabbrica separata. Ad esempio, ho una classe astratta chiamata IQueueItem e ho bisogno di un modo per tradurre quell'oggetto da e verso un altro oggetto (CloudQueueMessage). Quindi sull'interfaccia IQueueItem che ho -

public interface IQueueItem
{
    CloudQueueMessage ToMessage();
}

Ora, ho anche bisogno di un modo per la mia classe di coda effettiva per tradurre un oggetto CloudQueueMessage su un oggetto IQueue - cioè la necessità di una costruzione statica come IQueueItem objMessage = ItemType.FromMessage. Invece ho definito un'altra interfaccia IQueueFactory -

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

Ora posso finalmente scrivere la mia generica coda senza il nuovo vincolo () che nel mio caso era il problema principale.

public class AzureQueue<T> where T : IQueueItem
{
    private IQueueItemFactory<T> _objFactory;
    public AzureQueue(IQueueItemFactory<T> objItemFactory)
    {
        _objFactory = objItemFactory;
    }


    public T GetNextItem(TimeSpan tsLease)
    {
        CloudQueueMessage objQueueMessage = _objQueue.GetMessage(tsLease);
        T objItem = _objFactory.FromMessage(objQueueMessage);
        return objItem;
    }
}

ora posso creare un'istanza che soddisfi i criteri per me

 AzureQueue<Job> objJobQueue = new JobQueue(new JobItemFactory())

speriamo che questo possa aiutare qualcun altro un giorno, ovviamente un sacco di codice interno rimosso per cercare di mostrare il problema e la soluzione




Puoi farlo con un trucco generico, ma è ancora vulnerabile a ciò che Jon Skeet ha scritto:

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

La classe che implementa questa interfaccia deve avere un costruttore senza parametri:

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



Sarebbe molto utile se fosse possibile definire i costruttori nelle interfacce.

Dato che un'interfaccia è un contratto che deve essere utilizzato nel modo specificato. Il seguente approccio potrebbe essere un'alternativa valida per alcuni scenari:

public interface IFoo {

    /// <summary>
    /// Initialize foo.
    /// </summary>
    /// <remarks>
    /// Classes that implement this interface must invoke this method from
    /// each of their constructors.
    /// </remarks>
    /// <exception cref="InvalidOperationException">
    /// Thrown when instance has already been initialized.
    /// </exception>
    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;
    }

}



Sebbene non sia possibile definire una firma del costruttore in un'interfaccia, ritengo che valga la pena ricordare che questo potrebbe essere un punto da considerare in una classe astratta. Le classi astratte possono definire firme di metodo non astratte (astratte) allo stesso modo di un'interfaccia, ma possono anche aver implementato metodi e costruttori (concreti).

Lo svantaggio è che, poiché è un tipo di classe, non può essere utilizzato per nessuno degli scenari di tipo di ereditarietà multipli che un'interfaccia può fare.




Le interfacce sono Contract Interface non consentono campi, ovvero non è necessario inizializzare nulla. Interfaccia conserva solo il riferimento. L'interfaccia deve richiedere una classe derivata per contenere la memoria.




Related