Hallo zusammen,
ich habe ein Problem: Über eine ComboBox wähle ich aus einer Liste von Type-Objekten eine gewünschte Instanz aus. Dann möchte ich eine Dao-Klasse instanzieren, die mir Objekte des gewählten Typs aus der Datenbank holen kann.
Type selectedType = cmbTypes.SelectedItem as Type;
Dao<T> dao = new Dao<T>();
dao.GetAll();
...
Mein Problem ist jetzt, wie ich von der Type-Instanz auf eine Form komme, die ich im Dao als <T> einsetzen kann... 😦 Ist das überhaupt möglich? Das sind ja im Grunde Typennamen und Typeninstanzen die da aufeinander prallen...
Danke im Voraus
Wahrscheinlich suchst du sowas wie Activator.CreateInstance(Type t)
Hallo florian.reischer,
oder suchst du?
Type t = typeof(Dao<>).MakeGenericType(type);
Hallo florian.reischer
Wenn du wirklich mit dynamisch mit generischen Typen arbeiten musst, geht das erst ab .NET 3.5 wirklich. Du musst mit Type.GetType() eine typisierte Version des generischen Basistypen erzeugen. Über die ConstructorInfo kannst du dann eine Instanz erzeugen und diese in einen Basis-Typen casten.
Setzt jedoch voraus, dass deine Typen <T> alle vom gleichen Basistypen abgeleitet sind.
Grüße
Florian Reischl
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.
Wenn du wirklich mit dynamisch mit generischen Typen arbeiten musst, geht das erst ab .NET 3.5 wirklich. Du musst mit Type.GetType() eine typisierte Version des generischen Basistypen erzeugen.
Das verstehe ich jetzt nicht ganz - wieso soll das erst ab .NET 3.5 gehen bzw. was ist bei dir "dynamisch"?
Hi winSharp93
Sorry, mein Fehler... Ich meinte .NET 4.0 😁 - spielte auf Kovarianz an. Siehe mein Post hier
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.
Also ich habe das gestestet - und es geht nicht.
Etwas wie
List<object> list = new List<string>(new[] { "Hello", "World" });
ist nicht möglich. Und zwar aus gutem Grund; bei der List<object>
könntest du ohne weiteres einen int
hinzufügen. Und so einen Fehler zur Laufzeit zu kriegen ist nicht schön.
Implizit verwandeln kann man nur ein IEnumerable<_out_ T>
; List<T>
bleibt List<T>
und IList<T>
entsprechend auch.
Trotzdem geht es: Mit dem Schlüsselwort dynamic.
Ein bisschen Code:
static void TestGenericActivator(Type type, params object[] addItems)
{
// Schlüsselwort dynamic: Methoden werden intern über MethodInfo ausgelesen und aufgerufen -> geht bei passenden addItems
Console.WriteLine();
Console.WriteLine("Dynamic List");
dynamic dynamicList = Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
foreach (var item in (dynamic[])addItems)
dynamicList.Add(item);
foreach (var item in dynamicList)
Console.WriteLine(item);
// Cast: eine List<T> (wobei T nicht direkt object) kann man nicht zu einer List<object> casten; normale InvalidCastException
Console.WriteLine();
Console.WriteLine("Casted List");
List<object> castedList = (List<object>)(Activator.CreateInstance(typeof(List<>).MakeGenericType(type)));
// Hier (Laufzeit-)Exception: System.InvalidCastException was unhandled
// "Unable to cast object of type 'System.Collections.Generic.List`1[System.String]' to type 'System.Collections.Generic.List`1[System.Object]'."
foreach (var item in addItems)
castedList.Add(addItems);
foreach (var item in castedList)
Console.WriteLine(item);
}
Aufrufe:
TestGenericActivator(typeof(object), 'U', 2); // Problemlos
TestGenericActivator(typeof(string), "Hello", "World"); // Exception bei Cast
TestGenericActivator(typeof(float), 3, 1, 4, 1); // Exception bei Cast (alles ints)
TestGenericActivator(typeof(int), "Exception!!!"); // Exception bei beiden Varianten:
// Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled
// "The best overloaded method match for 'System.Collections.Generic.List<int>.Add(int)'
// has some invalid arguments"
Also: Mit Kovarianz geht auch nicht alles. Nur das, was idiotensicher ist (zu sein scheint).
mfg
SeeQuark
Danke für die schnellen Antworten, also was ich brauche ist sozusagen die statische Variante des Typs selectedType...
Normalerweise würde man so etwas tun um das Dao zu erzeugen:
Dao<Person> personDao = new Dao<Person>();
Person steht dabei allerdings als sozusagen "Keyword" für einen Datentyp. Ich habe nur das Typobjekt selber, quasi so:
Type personType = typeof(Person); und das kommt aus einer ComboBox. Eine Instanz eines Objekts vom Typ Person nutzt mir in diesem Fall auch nichts, da ich als Generic Type ja keine Instanz angeben kann. Ich nenne das was ich brauche einfach mal einen dynamischen Generic-Typ...
Implizit steht das schon im Post über mir; es geht nicht.
Schlüsselwort dynamic: Methoden werden intern über MethodInfo ausgelesen und aufgerufen
Etwas anderes fällt mir nicht ein, und gibt es IMHO auch nicht. Zu Reflection: [Artikel] Reflection und Metaprogrammierung.
mfg
SeeQuark
Das bedeutet dann wohl das die Variante nur funktioniert, in dem man ein riesiges if-else Würstchen auf den selectedItem der Combobox legt und sich dementsprechend die Daos herbeiholt... 😦 Dann werde ich mir wohl eine andere Methode überlegen 😉
Trick...
Deinem generischen Dao<> Typen von einem nicht generischen Typen ableiten. Den kannst du verwenden 😉
Grüße
Flo
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.
Hallo Florian
Das ist aber auch nur gefühlt besser als object zu benutzen 😉.
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Njain 😉
Ist einmal umständlich zu implementieren, aber in der Anwendung eigentlich okay. Beispiel einer generischen Liste für abgeleitete Typen welche von einem bestimmten Basistypen abgeleitet sind:
* Abstrakte Basis-Klasse welche IList<MyBasisType> explizit implementiert. Protected Methoden AddInternal(MyBasisType), RemoveInternal(MyBasisType), ... . Die expliziten Methoden von IList<> rufen als Proxy-Methoden die XyzInternal Methoden auf.
* Abgeleitete generische Klasse "MyList<T> where T : MyBasisType". Public Methoden Add/Remove/... welche ebenfalls als Proxy-Methoden die XyzInternal Methoden aufrufen.
Wie gesagt, einmal mehr Code. Hilft jedoch ungemein, wenn man viel bei großen Basis-Klassen.
Grüße
Flo
Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+
Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.