2016-12-06 5 views
3

Ich habe ein Objekt eines Typs zur Laufzeit bekannt und ich lese und Deserialisierung dieses Objekt aus der Datenbank. Es klappt. Nun würde Ich mag es zu einem gewissen Liste hinzuzufügen:Erstellen Sie eine Liste von generischen Objekten zur Laufzeit

private static List<T> generateList<T>() 
{ 
    List<T> lst = new List<T>(); 
    return lst; 
} 

private void readObjects(System.Type objType) 
{ 
    var methodInfo = typeof(My.Serializator).GetMethod("DeserializeDb"); 
    var genericMethod = methodInfo.MakeGenericMethod(objType1); 
    List<curType> currentList= generateList<curType>(); 
    // ...read stream from database and convert it to object 
    while (_rs.Read()) 
    { 
     var _objItem = genericMethod.Invoke(null, new[] { _streamedData }); 
     currentList.Add(_objItem); 
    } 
} 

Es wird nicht funktionieren. Der Fehler lautet:

curType ist eine Variable, wird aber wie ein Typ verwendet.

Wenn ich ändern Liste:

List<object> currentList = new List<object>(); 

es funktionieren wird. Aber kann ich das mit Generika (T) anstelle von Objekttyp machen?

+3

Nein, Sie können nicht erwarten, dass Ihr Compiler einen Typ ableitet, den Sie nur zur Laufzeit bereitstellen. Das, was auch immer du tust, benutze Reflektion oder was auch immer * wird immer nur 'Objekt' zurückgeben. Sie müssen beim Kompilieren wissen, welcher genaue Typ es tatsächlich ist. – HimBromBeere

+0

haben Sie versucht, Ihre Methode in readObjects () zu ändern? und zwicke deine Methode, um den Typ zu erhalten, der auf T basiert ... – Rex

+0

Wie nennst du 'ReadObjects'? Und was machst du danach mit 'currentList'? – HimBromBeere

Antwort

0

Sie easly Art der Liste erstellen, können Sie über Activator wollen, dann werfen zu IList und verwenden es:

private IList readObjects(System.Type objType) 
{ 
    var listType = typeof(List<>).MakeGenericType(curType); 
    var list = (IList)Activator.CreateInstance(listType); 

    // ... 

    while (_rs.Read()) 
    { 
     // ... 
     list.Add(_objItem); 
    } 
} 

list Instanz von List<YorActualType> sein wird.

aktualisiert

Wenn Sie Ihre Methode mit generischen Argumenten zu erklären, nehmen Sie Typinformationen während der Kompilierung zur Verfügung stellen. Andernfalls müssen Sie Reflexion verwenden.

Da Sie Typinformationen in Laufzeit bereitstellen (curType kann jede Art von Informationen enthalten), Compiler weiß nicht, was genau Typ verwendet wird, und Sie können Ihre Methode nicht erklären, etwas Konkretes zurückzugeben. Nur Abstraktionen erlaubt.

Lassen Sie uns mich zeigen auf etwas verrückt, aber anschauliches Beispiel:

var types = new [] { typeof(int), typeof(string) }; 
var rand = new Random(); 
var list = readObjects(types[rand.Next(0,2)]; 

Bis zum letzten Augenblick noch werden Sie nicht wissen, was genau Art der Liste erstellt wird. Compiler weiß es auch nicht. Compiler wird nie wissen, was genau Typ sollte verwendet werden, wenn Sie ihm nicht Ihre Typen bereitstellen. Wenn Sie Type verwenden, teilt es dem Compiler nur mit, dass einige reguläre Parameter mit dem Typ Type zur Laufzeit an die Methode übergeben werden. Es gibt keine Daten, die während der Kompilierzeit auf einen Typ schließen lassen. Diese Daten können nur über generic type parameters weitergegeben werden.

So gibt es mehrere Möglichkeiten, die Sie folgen können:

  1. genaue Arten Geben Sie bei der Kompilierung benötigen

    private List<T> readObjects<T>() 
    { 
        var objType = typeof(T); 
        var list = new List<T>(); 
        // rest of code.... 
    } 
    
  2. Verwenden Reflexion und Basistypen

    private IList readObjects(Type objType) 
    { 
        // rest of code with Activator and so on 
    } 
    

    Und Die spätere Verwendung hängt von Ihren Bedürfnissen ab. Wenn Sie wissen, welche Art Sie verwenden werden, konvertieren einfach:

    var list = (IList<MyType>)readObjects(typeof(myType)); 
    

    Aber ich denke, in diesem Fall eines bessere Nutzung Art und Weise # 1 mit generischem Argumente.

    Andernfalls werden Sie Reflexion verwenden.Oder einige Basisklassen, Schnittstellen und so weiter. Es hängt davon ab, welche Aufgabe Sie lösen werden.

P.S. Sie können mehr über generic types auf MSDN lesen.

+0

Dies hindert jedoch niemanden, eine Instanz eines anderen Typs in diese Liste zu bringen, zumindest nicht während der Kompilierung - Das ist unmöglich. Stattdessen erhalten Sie eine 'ArgumentException', die angibt, dass der angegebene Typ nicht zur generischen Liste hinzugefügt werden kann. – HimBromBeere

+0

@HimBromBeere sicher, es wird keine Kompilierzeitprüfungen stattfinden. Aber während der Laufzeit wird dies eine Ausnahme auslösen. Auch sein Mothod, um Daten zu erhalten, ist generisch, so unwahrscheinlich, dass Fehler geworfen werden. Ich glaube, dass diese Methode den Wert des generischen Argumenttyps zurückgibt. – lorond

+0

Danke. Es ist was ich wollte. Und wenn ich eine Methode habe, die diese Liste zurückgibt, wie soll ich sie dann deklarieren und aufrufen? private Liste readObjects (System.Type objType) – Simon

Verwandte Themen