Wie können benötigen Sie einen Konstruktor ohne Parameter für Typen, die Implementierung einer Schnittstelle?

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

Frage

Gibt es eine Möglichkeit?

Ich brauche alle Typen, die eine bestimmte Schnittstelle implementieren, um einen parameterlosen Konstruktor hat, kann es getan werden?

Ich bin der Entwicklung der Basis-code für andere Entwickler in meinem Unternehmen zum Einsatz, die in einem bestimmten Projekt.

Es ist ein Prozess, die Erzeugung von Instanzen von Typen (in unterschiedlichen threads), dass bestimmte Aufgaben auszuführen, und ich muss diesen Typen zu Folgen, einen bestimmten Vertrag (ergo, die Schnittstelle).

Die Schnittstelle wird intern für die Montage

Wenn Sie einen Vorschlag für dieses Szenario ohne Schnittstellen, ich werde gerne nehmen Sie es in Betracht...

War es hilfreich?

Lösung

Juan Manuel sagte:

das ist einer der Gründe, warum ich nicht verstehen, warum es nicht Bestandteil des Vertrages, in der Schnittstelle

Es ist ein Indirekter Mechanismus.Die generische ermöglicht Sie zu "betrügen" und senden, geben Sie Informationen zusammen mit der Schnittstelle.Die kritische Sache zu erinnern ist hier, dass die Einschränkung, die nicht auf das interface, mit dem Sie arbeiten direkt.Es ist keine Einschränkung auf die Schnittstelle selbst, aber auf eine andere Art, die "ride along" auf dem interface.Dies ist die beste Erklärung, die ich anbieten kann, fürchte ich.

Zur Veranschaulichung dieser Tatsache, werde ich darauf hinweisen, ein Loch, das ich bemerkt habe, in aku code.Es ist möglich, eine Klasse schreiben, dass würde kompilieren in Ordnung, aber zur Laufzeit scheitern, wenn Sie versuchen, Sie zu instanziieren:

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

Etwas leitet sich von ITest<T>, sondern implementiert keinen parameterlosen Konstruktor.Es kompiliert fein, da String nicht implementiert einen parameterlosen Konstruktor.Wieder die Einschränkung auf T, und daher Zeichenfolge, anstatt ITest oder so Etwas.Da die Einschränkung auf T zufrieden ist, dies kompiliert.Aber es werden nicht zur Laufzeit.

Um zu verhindern, dass einige Instanzen von diesem problem, müssen Sie ein weiteres Hindernis für T, wie unten:

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

Beachten Sie die neue Einschränkung:T :ITest<T>.Diese Einschränkung gibt an, dass das, was Sie gehen in das argument parameter von ITest<T> muss auch ableiten von ITest<T>.

Auch so wird dies nicht verhindern alle Fälle das Loch.Der folgende code kompiliert fein, da Sie Eine hat einen parameterlosen Konstruktor.Aber da B parameterlosen Konstruktor privat ist, instanziieren B mit Ihr Prozess zur Laufzeit scheitern.

public class A : ITest<A>
{
}

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

Andere Tipps

Nicht zu stumpf, aber du hast missverstanden den Zweck der Schnittstellen.

Eine Schnittstelle bedeutet, dass einige Menschen implementieren können, in eigenen Klassen, und übergeben Sie dann Instanzen dieser Klassen auf andere Klassen verwendet werden.Schöpfung entsteht eine unnötig starke Kopplung.

Es klingt wie Sie wirklich brauchen eine Art von system für die Registrierung, entweder haben die Leute registrieren Instanzen nutzbar Klassen, die das interface implementieren oder von Fabriken, die können schaffen, sagte Produkten auf Anfrage.

Juan,

Leider gibt es keine Möglichkeit, dies zu umgehen, in eine stark typisierte Sprache.Sie werden nicht in der Lage zu gewährleisten, zur compile-Zeit, dass die Klassen werden in der Lage sein, um instanziiert zu werden, indem Sie Ihren Aktivator-code.

(ed:entfernt eine falsche alternative Lösung)

Der Grund ist, dass, leider, es ist nicht möglich, Sie zu verwenden-Schnittstellen, abstrakte Klassen, oder virtuelle Methoden in Kombination mit Konstruktoren oder statische Methoden.Der kurze Grund dafür ist, dass die ehemaligen enthalten keine expliziten geben Sie Informationen, und die letzteren erfordern eine explizite Typ-Informationen.

Konstruktoren und statische Methoden muss explizite (direkt im code) - Typ verfügbaren Informationen zum Zeitpunkt des Aufrufs.Dies ist erforderlich, da es keine Instanz der Klasse beteiligt, die kann abgefragt werden, indem die Laufzeit zu erhalten, den zugrunde liegenden Typ, der die Laufzeit muss, um festzustellen, welche tatsächlichen konkreten Methode zu nennen.

Der gesamte Punkt eines interface, abstract class, oder virtuelle Methode ist in der Lage zu sein einen Aufruf der Funktion ohne explizite geben Sie Informationen, und ermöglicht wird dies durch die Tatsache, dass es eine Instanz verwiesen wird, die "versteckte" Art von Informationen, die nicht direkt an den aufrufenden code.So sind diese beiden Mechanismen sind Recht einfach ausschließen.Sie können nicht verwendet werden zusammen, weil, wenn Sie mischen Sie Sie am Ende mit keine konkreten Informationen überall, was bedeutet, dass die Laufzeit hat keine Ahnung, wo zu finden die Funktion Sie Fragen Sie zu rufen.

Sie können verwenden type parameter constraint

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

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

Sie müssen also eine Ding erstellen Instanzen von einem unbekannten Typ, der eine Schnittstelle implementiert.Sie haben grundsätzlich drei Optionen:ein factory-Objekt, ein Textobjekt oder ein Delegierter.Hier die Gegebenheiten:

public interface IInterface
{
    void DoSomething();
}

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

Verwendung von Typ ist ziemlich hässlich, aber Sinn macht, in einigen Szenarien:

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

Das größte problem mit ihm ist, dass zur compile-Zeit, haben Sie keine Garantie, dass Foo eigentlich hat ein Standard-Konstruktor.Auch die Reflexion ist ein bisschen langsam, wenn dies geschieht zu werden, performance-kritischen code.

Die häufigste Lösung ist die Verwendung einer factory:

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 der oben genannten, IFactory ist, was wirklich zählt.Factory ist eine convenience-Klasse für Klassen, do eine Standard-Konstruktor.Dies ist die einfachste und oft die beste Lösung.

Der Dritte derzeit ungewöhnlich-aber-wahrscheinlich-zu-sich-mehr-gängige Lösung ist die Verwendung eines Delegaten:

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

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

Der Vorteil hier ist, dass der code ist kurz und einfach, kann Arbeit mit alle Methode der Konstruktion, und (mit-Verschlüsse) können Sie problemlos weitergeben können zusätzliche Daten, die benötigt werden zum erstellen der Objekte.

Rufen Sie eine RegisterType-Methode mit dem Typ, und beschränken Sie die Verwendung von Generika.Dann, anstatt zu Fuß Baugruppen zu finden, ITest implementors, nur speichern Sie Sie und erstellen Sie von dort aus.

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

Ich denke nicht.

Sie können auch nicht verwenden Sie eine abstrakte Klasse für diese.

Ich möchte alle daran erinnern, dass:

  1. Schreiben von Parametern in .NET ist einfach
  2. Schreiben statische Analyse-tools .NET, die gewährleisten, dass die übereinstimmung mit der Unternehmens-standards ist einfach

Ein tool zu schreiben, um schnappen Sie sich alle konkreten Klassen implementieren eine bestimmte Schnittstelle/ein Attribut überprüfen und sicherstellen, dass es hat einen parameterlosen Konstruktor dauert etwa 5 Minuten Programmieraufwand.Fügen Sie es zu Ihrem post-build-Schritt, und jetzt müssen Sie einen Rahmen für die was auch immer andere statische Analysen, die Sie durchführen müssen.

Die Sprache, den compiler, die IDE, Ihr Gehirn - Sie sind alle tools.Verwenden Sie Sie!

Nein, Sie können nicht tun, dass.Vielleicht auch für Ihre situation eine factory-Schnittstelle wäre hilfreich?Etwas wie:

interface FooFactory {
    Foo createInstance();
}

Bei jeder Implementierung von Foo erstellen Sie eine Instanz von FooFactory, der weiß, wie um es zu schaffen.

Sie brauchen nicht einen parameterlosen Konstruktor für den Aktivator zu instanziieren der Klasse.Sie haben einen parametrisierten Konstruktor und übergeben Sie alle Parameter aus dem Activator.Check-out Auf dieser MSDN.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top