75 Stimmen

Initialisieren einer generischen Variable aus einer C#-Typvariablen

Ich habe eine Klasse, die einen generischen Typ als Teil ihrer Initialisierung benötigt.

public class AnimalContext
{
    public DoAnimalStuff()
    {
        //AnimalType-spezifischer Code
    }
}

Was ich im Moment tun kann, ist

AnimalContext donkeyContext = new AnimalContext();
AnimalContext orcaContext = new AnimalContext();

Aber was ich tun möchte oder muss, ist in der Lage zu sein, eine AnimalContext initialisiert auf einen Typen zu deklarieren, der nur zur Laufzeit bekannt ist. Zum Beispiel,

Animal a = MeinLieblingstier(); //gibt eine Instanz einer Klasse zurück, die ein Tier implementiert
AnimalContext a_Context = new AnimalContext();
a_Context.DoAnimalStuff();

Ist das überhaupt möglich? Ich kann online keine Antwort darauf finden.

74voto

jason Punkte 227577

Was bedeutet dieser Teil ist möglich:

new AnimalContext();

Offensichtlich ist diese genaue Syntax falsch, und wir werden darauf eingehen, aber es ist möglich, eine Instanz eines generischen Typs zur Laufzeit zu erstellen, wenn Sie die Typparameter nicht bis zur Laufzeit kennen.

Was Sie mit diesem Teil meinen ist nicht:

AnimalContext a_Context

Es ist also unmöglich, eine Variable als generischen Typ zu deklarieren, wenn Sie die Typparameter zur Kompilierungszeit nicht kennen. Generika sind Kompilierungszeitkonstrukte und setzen voraus, dass die Typinformationen zur Kompilierungszeit verfügbar sind. Wenn Sie die Typen zur Kompilierungszeit nicht kennen, verlieren Sie alle Vorteile der Generika.

Um jedoch eine Instanz eines generischen Typs zur Laufzeit zu erstellen, wenn Sie den Typ bis zur Laufzeit nicht kennen, können Sie folgendes sagen:

var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);   

Beachten Sie, dass der Typ zur Kompilierungszeit von a_context object ist. Sie müssen a_context in einen Typ oder ein Interface umwandeln, das die Methoden enthält, auf die Sie zugreifen möchten. Oft sieht man Leute hier den generischen Typ AnimalContext implementieren ein Interface (sagen wir IAnimalContext) oder von einer nicht generischen Basisklasse erben (sagen wir AnimalContext), die die benötigten Methoden definiert (so können Sie a_context in das Interface oder die nicht generische Basisklasse umwandeln). Eine andere Alternative ist die Verwendung von dynamic. Aber denken Sie daran, dass Sie dadurch keinen der Vorteile von generischen Typen haben.

13voto

cuongle Punkte 71553

Sie können Reflexion mit generischen Typen verwenden, indem Sie die Methode MakeGenericType verwenden und vom Schlüsselwort dynamic Gebrauch machen:

var type = typeof (AnimalContext<>).MakeGenericType(a.GetType());
dynamic a_Context = Activator.CreateInstance(type);

So können Sie aufrufen:

a_Context.DoAnimalStuff();

Oder verwenden Sie erneut Reflexion, um die Methode aufzurufen:

type.GetMethod("DoAnimalStuff").Invoke(a_Context, null);

6voto

SCB Punkte 2854

Sie müssten den Typ mithilfe von Reflection erstellen und dann diesen Typ aufrufen. Etwas in der Art:

Animal a = MyFavoriteAnimal();
var contextType = typeof(EsbRepository<>).MakeGenericType(a.GetType());

dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();

Die Verwendung von dynamic bedeutet, dass die Kontextvariable zur Laufzeit ausgewertet wird und es Ihnen ermöglicht, die Methode DoAnimalStuff aufzurufen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X