Laden...

Über Reflection herausfinden wer eine bestimmte abstrakte Klasse implementiert?

Erstellt von kuku-ba vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.823 Views
K
kuku-ba Themenstarter:in
26 Beiträge seit 2005
vor 15 Jahren
Über Reflection herausfinden wer eine bestimmte abstrakte Klasse implementiert?

Hallo Community,

ich möchte über Reflection herausfinden, welche Klasse eine bestimmte abstrakte Klasse implementiert?
Konkret möchte ich zur Laufzeit prüfen, ob die gegebene Datenstruktur den richtigen Datentyp enthält. Zum Beispiel: In der Datenstruktur ist der Datentyp RGB enthalten, aber die Datenstruktur sollte als Datentyp ComplexNumber enthalten.

Den Code habe ich schon, fast komplett. Es fehlt nur diese kleine Kleinigkeit:


          // Die Klasse RGBComplexConverter hat als Basisklasse die abstrakte Klasse
         Type myType = typeof(RGBComplexNumberConverter); // Hier möchte ich stattdessen über die akstrakte Klasse herausfinden welche Klassen sie implementieren


            Array2D array2D = new Array2D(typeof(RGB), 3, 5);
            Random r = new Random();
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 5; j++) {
                    array2D.Add(new RGB((byte) r.Next(0, 255), (byte) r.Next(0, 255), (byte) r.Next(0, 255)), i, j);
                }
            }
            // Erst Konstruktor holen
            ConstructorInfo info = myType.GetConstructor(new Type[] {});
            // Konstruktor ausführen
            object o = info.Invoke(new object[] {});
            // Methode holen
            MethodInfo methodInfo = myType.GetMethod("ConvertTo");
            // Methode ausführen
            IDataStructure structure1 = (IDataStructure) methodInfo.Invoke(o, new object[] { array2D });


Ich hoffe ihr könnt mir helfen. In der API hab ich nichts gefunden.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo kuku-ba,

soweit ich weiß, geht nur der umgekehrte Weg. Du kannst also fragen, ob einen bestimmt Klasse von deiner abstrakten Basisklasse abgeleitet ist.

Im Zweifel muss du eine Schleife über alle (relevanten) Assemblies und dort über alle Typen machen und für jeden Typ fragen, ob er von deiner Basisklasse abgeleitet ist.

herbivore

K
kuku-ba Themenstarter:in
26 Beiträge seit 2005
vor 15 Jahren

Danke für die Antwort.

Hab jetzt die Lösung, dank dir:


Assembly assembly = Assembly.GetAssembly(typeof (AConverter));
            foreach (Type type in assembly.GetTypes()) {
                if (type.BaseType == typeof(AConverter)) {
                    Console.WriteLine(type.FullName);
                }
            }

Somit kann ich dynamisch zur Laufzeit den richtigen Konverter aufrufen.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo kuku-ba,

type.BaseType == typeof(AConverter)  

das berücksichtigt allerdings keine indirekte Vererbung. Verwende besser Type.IsSubclassOf.

herbivore

O
778 Beiträge seit 2007
vor 15 Jahren

Type.IsSubclassOf funktioniert solange, wie die Basisklasse abstrakt ist. Wenn du dich aber irgendwann dafür entscheiden solltest, die Basisklasse nicht mehr abstrakt zu machen, oder aber du machst das was jetzt die abstrakte Basisklasse ist zu einer Schnittstelle, dann wäre Type.IsAssignableOf das Mittel der Wahl.

Letztenendes ist als Type.IsSubclassOf die performantere, Type.IsAssignableOf die allgemeinere und damit wartungssicherere Lösung.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo onlinegurke,

ob die Basisklasse abstrakt ist, spielt keine Rolle. Auch bei konkreten Basisklassen würde Type.IsSubclassOf bei Unterklassen true liefern. Oder meinst du, dass Type.IsSubclassOf bei konkreten Klassen deshalb nicht funktionieren würde, weil es für eben ein solche konkretes Objekt nicht true liefern würde, weil eine Klasse keine Unterklasse von sich selbst ist?

herbivore

O
778 Beiträge seit 2007
vor 15 Jahren

eben ein solche konkretes Objekt nicht true liefern würde, weil eine Klasse keine Unterklasse von sich selbst ist?

genau das meinte ich 🙂

Der Name impliziert das zumindest, ich habs aber nicht geprüft. Aber in jedem Fall geht IsSubclassOf nicht über die Schnittstellen. Was allerdings ganz klar gegen IsAssignableOf spricht ist die Tatsache, dass man sehr leicht Gefahr läuft die beiden Type-Objekte, die man da braucht, zu verwechseln, weil man es intuitiv falsch macht 😦. Für mich ist es der Inbegriff der Tatsache, dass Namenskonventionen manchmal auch nach hinten losgehen können...

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo onlinegurke,

wieso Namenskonventionen? Es heißt ja IsAssignableFrom und nicht IsAssignableOf. Es hätte genauso gut IsAssignableTo heißen können. From oder To war also eine Designentscheidung. Es sind also nicht die Namenskonvention, die Schuld waren. 🙂

herbivore

O
778 Beiträge seit 2007
vor 15 Jahren

ich meine, wenn ich das lese

if (typeof(int).IsAssignableFrom(typeof(object)))
            {
            }

Dann würde ich eigentlich vermuten, dass da ausgewertet werden soll, ob ints objects zugewiesen werden können. Also wenn ich eine object-Variable habe, ob ich der ein int-Objekt zuweisen kann. Es wird aber genau andersrum ausgewertet, nämlich ob objects ints zugewiesen werden können, also wenn ich eine int-Variable habe, ob dann object zulässig ist. Währenddessen

typeof(int).IsSubclassOf(typeof(object))

nach Intuition erwartungsgemäß auswertet, ob int ein Unterklasse von object ist.

Aber stimmt, mit Namenskonventionen hat das eigentlich weniger was zu tun, da hat einfach nur jemand Scheiße gebaut bei der Benennung dieser Funktion.

Ich hatte im Gegenteil versucht nachzuvollziehen, warum jemand den Namen so vermurkst haben könnte und bin zu dem Schluss gekommen, er kann eigentlich nur wegen Konventionen dazu getrieben worden sein...

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo onlinegurke,

Dann würde ich eigentlich vermuten, dass da ausgewertet werden soll, ob ints objects zugewiesen werden können.

hm, weiß nicht, wie du darauf kommst. Für mich ergibt sich aus dem Namen genau das, was auch tatsächlich passiert. Der Parameter von IsAssignableFrom ist - wie der Name sagt - der Typ des From-Werts, also der Typ des Werts auf der rechten Seite der Zuweisung.

herbivore