Come si può richiedere un costruttore senza parametri per i tipi di implementazione di un'interfaccia?

StackOverflow https://stackoverflow.com/questions/26903

Domanda

C'è un modo?

Ho bisogno di tutti i tipi che implementano un'interfaccia specifica per avere un costruttore senza parametri, può essere fatto?

Sto sviluppando il codice di base per gli altri sviluppatori in mia compagnia per l'utilizzo in un progetto specifico.

C'è un processo che consentirà di creare istanze di tipi (in diversi thread) che svolgono determinati compiti, e ho bisogno di questi tipi di seguire uno specifico contratto (ergo, l'interfaccia).

L'interfaccia interna per il montaggio

Se hai un suggerimento per questo scenario senza interfacce, io sarò lieta di prenderla in considerazione...

È stato utile?

Soluzione

Juan Manuel ha detto:

che uno dei motivi per cui non capisco perché non può essere una parte del contratto nell'interfaccia

E ' un meccanismo indiretto.Generico consente di "barare" e invio di informazioni di tipo lungo con l'interfaccia.La cosa più importante da ricordare è che il vincolo non è l'interfaccia che si sta lavorando direttamente con.Non è un vincolo sulla stessa interfaccia, ma su qualche altro tipo di "giro lungo" sull'interfaccia.Questa è la migliore spiegazione che posso offrire, ho paura.

A titolo di esempio di questo fatto, io punto su un buco che ho notato in aku codice.È possibile scrivere una classe che potrebbe compilare bene, ma non riescono a runtime quando si tenta di creare un'istanza:

public class Something : ITest<String>
{
  private Something() { }
}

Qualcosa che deriva da ITest<T>ma implementa nessun costruttore senza parametri.Per compilare bene, poiché la Stringa di non implementare un costruttore senza parametri.Di nuovo, il vincolo è a T, e, pertanto, Stringa, piuttosto che ITest o Qualcosa del genere.Dal momento che il vincolo di T è soddisfatto, questo verrà compilato.Ma avrà esito negativo in fase di runtime.

Per evitare alcuni le istanze di questo problema, è necessario aggiungere un altro vincolo a T, come di seguito:

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

Nota il nuovo vincolo:T :ITest<T>.Questo vincolo di specifica che quello che ti passa l'argomento parametro di ITest<T> deve anche derivare da ITest<T>.

Anche così, questo non impedirà tutti casi del foro.Il codice riportato di seguito compilare bene, perché ha un costruttore senza parametri.Ma dal momento che B costruttore senza parametri è privata che crea un'istanza di B con il processo avrà esito negativo in fase di runtime.

public class A : ITest<A>
{
}

public class B : ITest<A>
{
  private B() { }
}

Altri suggerimenti

Non essere troppo schietto, ma hai frainteso lo scopo di interfacce.

Un'interfaccia significa che più persone in grado di implementare nelle loro classi, e quindi passare le istanze di queste classi di altre classi.Creazione, è un inutile accoppiamento forte.

Sembra che si ha realmente bisogno di un qualche tipo di sistema di registrazione, sia per avere persone a registrarsi casi di utilizzabile classi che implementano l'interfaccia, o di stabilimenti che si possono creare tali articoli su richiesta.

Juan,

Purtroppo non c'è modo di ottenere tutto questo in un linguaggio fortemente tipizzato.Non sarà in grado di garantire in fase di compilazione che le classi saranno in grado di essere istanziati dal tuo Attivatore a base di codice.

(ndr:rimosso da un'erronea soluzione alternativa)

Il motivo è che, purtroppo, non è possibile utilizzare le interfacce, classi astratte, o metodi virtuali in combinazione con i costruttori o i metodi statici.Il breve motivo è che il primo non contengono espliciti tipo di informazioni, e questi ultimi richiedono esplicita del tipo di informazioni.

Costruttori e metodi statici deve espliciti (a destra c'è il codice) tipo di informazioni disponibili al momento della chiamata.Questo è necessario perché non c'è istanza della classe in questione che può essere interrogato dal runtime di ottenere il tipo sottostante, che il runtime deve determinare quali concrete ed effettive metodo da chiamare.

L'intero punto di un'interfaccia, classe astratta, virtuale o metodo è quello di essere in grado di effettuare una chiamata di funzione senza esplicito il tipo di informazioni, e questo è permesso dal fatto che c'è un'istanza a cui si fa riferimento, che ha "nascosto" il tipo di informazioni che non sono direttamente disponibili al codice chiamante.Così questi due meccanismi sono semplicemente, che si escludono a vicenda.Essi non possono essere utilizzati insieme, perché quando li mescoli, si finisce con nessun tipo concreto a tutte le informazioni ovunque, il che significa che il runtime non ha idea di dove trovare la funzione che si sta chiedendo di chiamare.

È possibile utilizzare parametro tipo di vincolo

interface ITest<T> where T: new()
{
    //...
}

class Test: ITest<Test>
{
    //...
}

Quindi, avete bisogno di un cosa che possono creare istanze di un tipo sconosciuto che implementa un'interfaccia.Hai fondamentalmente tre opzioni:una fabbrica di oggetti, un Tipo di oggetto, o un suo delegato.Ecco i dati di fatto:

public interface IInterface
{
    void DoSomething();
}

public class Foo : IInterface
{
    public void DoSomething() { /* whatever */ }
}

Utilizzando il Tipo è abbastanza brutto, ma ha un senso in alcuni scenari:

public IInterface CreateUsingType(Type thingThatCreates)
{
    ConstructorInfo constructor = thingThatCreates.GetConstructor(Type.EmptyTypes);
    return (IInterface)constructor.Invoke(new object[0]);
}

public void Test()
{
    IInterface thing = CreateUsingType(typeof(Foo));
}

Il più grande problema è che in fase di compilazione, non avete nessuna garanzia che Pippo in realtà ha un costruttore di default.Inoltre, la riflessione è un po ' lento se questo accade a essere critici per le prestazioni del codice.

La soluzione più comune è quello di utilizzare una fabbrica:

public interface IFactory
{
    IInterface Create();
}

public class Factory<T> where T : IInterface, new()
{
    public IInterface Create() { return new T(); }
}

public IInterface CreateUsingFactory(IFactory factory)
{
    return factory.Create();
}

public void Test()
{
    IInterface thing = CreateUsingFactory(new Factory<Foo>());
}

In precedenza, IFactory è ciò che conta davvero.La fabbrica è solo per comodità di classe per le classi che fare fornire un costruttore predefinito.Questo è il più semplice e spesso la soluzione migliore.

Il terzo attualmente-non comune-ma-probabilmente-per-diventare-piu-soluzione più comune è l'utilizzo di un delegato:

public IInterface CreateUsingDelegate(Func<IInterface> createCallback)
{
    return createCallback();
}

public void Test()
{
    IInterface thing = CreateUsingDelegate(() => new Foo());
}

Il vantaggio qui è che il codice è breve e semplice, in grado di lavorare con qualsiasi metodo di costruzione, e (con chiusure) consente di passare insieme altri dati necessari per costruire gli oggetti.

Chiamare un RegisterType metodo con il tipo, e limitano l'uso di farmaci generici.Quindi, invece di camminare assemblee per trovare ITest le parti, archiviare e creare da lì.

void RegisterType<T>() where T:ITest, new() {
}

Io non la penso così.

È inoltre possibile utilizzare una classe astratta per questo.

Vorrei ricordare a tutti che:

  1. La scrittura di attributi .NET è facile
  2. La scrittura di strumenti di analisi statica in .NET che garantire la conformità con gli standard aziendali è facile

La scrittura uno strumento per afferrare tutte le classi concrete che implementare una determinata interfaccia/avere un attributo e verificando che ha un costruttore senza parametri prende circa 5 minuti di sforzo codifica.La puoi aggiungere al tuo post-passaggio di generazione e ora avete un quadro di riferimento per qualsiasi altra analisi statica che è necessario eseguire.

La lingua, il compilatore, l'IDE, il cervello, sono tutti strumenti.Li uso!

No, non puoi farlo.Forse per la situazione in fabbrica l'interfaccia potrebbe essere utile?Qualcosa di simile a:

interface FooFactory {
    Foo createInstance();
}

Per ogni implementazione di Pippo si crea un'istanza di FooFactory che sa creare.

Non hai bisogno di un costruttore senza parametri per l'Attivatore per creare un'istanza di una classe.Si può avere un costruttore con parametri e passare tutti i parametri dell'Attivatore.Check out MSDN su questo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top