none
dynamische Klassen... RRS feed

  • Frage

  • und noch 2 Sachen :

    a) kann ich prüfen ob eine Klasse eine bestimmte Funktion oder Sub hat ? Irgendwie so mit HasFunction(oPersonal, "MenuRecordSave") ?
    b) kann ich Klassen auch dynamisch erzeugen ? z.B.

    CLASS A
    private Func XYZ()
    return 0

    CLASS B
    private Func XYZ()
    return 0


    CLASS C
    private sub InitalleandereKlassen()
     dim aKlassen as ARRAY

     aKlassen = {"CLASSA","CLASSB"}

    end sub

    nun möcht ich diese Klassen in dem Array einmal erzeugen und die Methode/Sub XYZ anspringen und dann wieder
    schliessen...
    Das Array wird später ca. 400 Objekte beinhalten also möcht ich mir das händische tippen erleichtern :)

    Mario

    Mittwoch, 30. Juni 2010 09:17

Antworten

  • Hallo Mario,

    a) kann ich prüfen ob eine Klasse eine bestimmte Funktion oder Sub hat ? Irgendwie so mit HasFunction(oPersonal, "MenuRecordSave") ?

    Ja, das geht mittels Reflection. Mal in einem einfachen Beispiel:

     ' Imports System.Reflection
    
     Public Function HasMethod(ByVal obj As Object, ByVal name As String) As Boolean
    
      Dim mi As MethodInfo = obj.GetType.GetMethod(name, BindingFlags.Instance Or _
                                BindingFlags.Public Or _
                                BindingFlags.NonPublic)
    
      Return mi IsNot Nothing
    
     End Function
    

    b) kann ich Klassen auch dynamisch erzeugen ? z.B.

    Wenn ich Dich hier richtig verstehe, möchtest Du die Klasse dynamisch auf Basis einer Zeichenfolge instantiieren, richtig?

      Dim o As Object
      Dim t As System.Type
    
      t = Assembly.GetExecutingAssembly().GetType("WindowsApplication1.Class1")
    
      o = Activator.CreateInstance(t)
    
      If o IsNot Nothing Then
    
       Dim mi As MethodInfo = t.GetMethod("Foo", BindingFlags.Instance Or _
                            BindingFlags.Public)
    
       If mi IsNot Nothing Then
        mi.Invoke(o, Nothing)
       End If
      End If
    

    Kurz erklärt: Aus dem aktuell ausführendem Assembly wird der Typ auf Basis des vollständigen Klassennamens ermittelt. Beachte hier, dass der angegebene Namespace ggf. anzupassen ist, je nachdem welchen Stammnamespace Du in den Projekt Eigenschaften bzw. die Namespace Anweisung festgelegt hast. Activator.CreateInstance erstellt eine Instanz aus diesem Typ. Danach erfolgt die bereits im ersten Beispiel gezeigte Ermittlung der Methode und der Aufruf selbiger.

    Du solltest aber beachten, dass Reflection auf Seiten der Runtime eine eher aufwändige Angelegenheit ist und sich negativ auf die Performance auswirken kann. Gerade wenn Du hier später 400 Objekte ins Spiel bringen möchtest. Vielleicht magst Du ja den Hintergrund Deines Vorgehens erklären. So kann man sehen, ob es bessere Herangehensweisen gibt.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Mittwoch, 30. Juni 2010 10:38
  • Hallo Mario,

    Das dynamische Erzeugen der Klassen sind nacher Klassen für jede Tabelle im SQL/Access Datenbank. Diese Klassen behinhalten die aktuelle Strutkur, Indexe, genauere Feldbeschreibungen, Eingabemaskenformate für Textboxen, Delete Methoden um abhängige Tabelleneinträge unter Umständen ebenfalls mit zu löschen ) und viele weitere Informationen.

    Klingt fast so, als wolltest Du einen O/R Mapper, wie das Entity Framework noch einmal neu erfinden.

    JEde Klasse verfügt über ein und die selbe Function nur zur Sicherheit deshalb die Abfrage mit "Hasfunktion" falls jemand anderes mal diese Funkttion später vergisst an der Klasse das zu definieren...

    Dass Klassen über bestimmte Eigenschaften und Methoden verfügen, legt man in der OOP meist über Interfaces fest. Damit kannst Du eine Klasse erzeugen und prüfst, ob die Klasse dieses Interface implementiert. Wenn sie das macht, kannst Du über dieses Interface typsicher auf die Methode zugreifen und kannst sicher sein, dass sie implementiert vorhanden ist. Am Beispiel von gestern:

    Public Interface IFoo
     Sub Foo()
    End Interface
    
    Public Class Class1
     Implements IFoo
    
     Public Sub Foo() Implements IFoo.Foo
     MsgBox("Foo")
     End Sub
    End Class
    
    ' Anwendung:
    
     Dim o As Object
     Dim t As System.Type
    
     Dim lClass As String = "CreateInstanceAndMethodInfo.Class1"
    
     t = Assembly.GetExecutingAssembly().GetType(lClass)
    
     If t IsNot Nothing Then
     o = Activator.CreateInstance(t)
    
     If TypeOf o Is IFoo Then
     DirectCast(o, IFoo).Foo()
     End If
     End If

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Donnerstag, 1. Juli 2010 07:31

Alle Antworten

  • Hallo Mario,

    a) kann ich prüfen ob eine Klasse eine bestimmte Funktion oder Sub hat ? Irgendwie so mit HasFunction(oPersonal, "MenuRecordSave") ?

    Ja, das geht mittels Reflection. Mal in einem einfachen Beispiel:

     ' Imports System.Reflection
    
     Public Function HasMethod(ByVal obj As Object, ByVal name As String) As Boolean
    
      Dim mi As MethodInfo = obj.GetType.GetMethod(name, BindingFlags.Instance Or _
                                BindingFlags.Public Or _
                                BindingFlags.NonPublic)
    
      Return mi IsNot Nothing
    
     End Function
    

    b) kann ich Klassen auch dynamisch erzeugen ? z.B.

    Wenn ich Dich hier richtig verstehe, möchtest Du die Klasse dynamisch auf Basis einer Zeichenfolge instantiieren, richtig?

      Dim o As Object
      Dim t As System.Type
    
      t = Assembly.GetExecutingAssembly().GetType("WindowsApplication1.Class1")
    
      o = Activator.CreateInstance(t)
    
      If o IsNot Nothing Then
    
       Dim mi As MethodInfo = t.GetMethod("Foo", BindingFlags.Instance Or _
                            BindingFlags.Public)
    
       If mi IsNot Nothing Then
        mi.Invoke(o, Nothing)
       End If
      End If
    

    Kurz erklärt: Aus dem aktuell ausführendem Assembly wird der Typ auf Basis des vollständigen Klassennamens ermittelt. Beachte hier, dass der angegebene Namespace ggf. anzupassen ist, je nachdem welchen Stammnamespace Du in den Projekt Eigenschaften bzw. die Namespace Anweisung festgelegt hast. Activator.CreateInstance erstellt eine Instanz aus diesem Typ. Danach erfolgt die bereits im ersten Beispiel gezeigte Ermittlung der Methode und der Aufruf selbiger.

    Du solltest aber beachten, dass Reflection auf Seiten der Runtime eine eher aufwändige Angelegenheit ist und sich negativ auf die Performance auswirken kann. Gerade wenn Du hier später 400 Objekte ins Spiel bringen möchtest. Vielleicht magst Du ja den Hintergrund Deines Vorgehens erklären. So kann man sehen, ob es bessere Herangehensweisen gibt.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Mittwoch, 30. Juni 2010 10:38
  • Hallo Thorsten,

    super vielen Dank! Werde es gleich heute Nachmittag ausprobieren.

    Das dynamische Erzeugen der Klassen sind nacher Klassen für jede Tabelle im SQL/Access Datenbank. Diese Klassen behinhalten die aktuelle Strutkur, Indexe, genauere Feldbeschreibungen, Eingabemaskenformate für Textboxen, Delete Methoden um abhängige Tabelleneinträge unter Umständen ebenfalls mit zu löschen ) und viele weitere Informationen.

    Schätzungsweise werden es ca. 400 Tabellen später werden. Und somit will ich jede Klasse bei Programmstart einmal erzeugen, die Klasse sich selbst auf Struktur ( mit ggfs. Update ) und Vorhandensein prüfen lassen. Das funtkioniert schon alles. Nur muss ich das Objekt zur Zeit noch "händisch eintippen".. JEde Klasse verfügt über ein und die selbe Function nur zur Sicherheit deshalb die Abfrage mit "Hasfunktion" falls jemand anderes mal diese Funkttion später vergisst an der Klasse das zu definieren...

    bye,

    Mario

    Donnerstag, 1. Juli 2010 06:59
  • Hallo Mario,

    Das dynamische Erzeugen der Klassen sind nacher Klassen für jede Tabelle im SQL/Access Datenbank. Diese Klassen behinhalten die aktuelle Strutkur, Indexe, genauere Feldbeschreibungen, Eingabemaskenformate für Textboxen, Delete Methoden um abhängige Tabelleneinträge unter Umständen ebenfalls mit zu löschen ) und viele weitere Informationen.

    Klingt fast so, als wolltest Du einen O/R Mapper, wie das Entity Framework noch einmal neu erfinden.

    JEde Klasse verfügt über ein und die selbe Function nur zur Sicherheit deshalb die Abfrage mit "Hasfunktion" falls jemand anderes mal diese Funkttion später vergisst an der Klasse das zu definieren...

    Dass Klassen über bestimmte Eigenschaften und Methoden verfügen, legt man in der OOP meist über Interfaces fest. Damit kannst Du eine Klasse erzeugen und prüfst, ob die Klasse dieses Interface implementiert. Wenn sie das macht, kannst Du über dieses Interface typsicher auf die Methode zugreifen und kannst sicher sein, dass sie implementiert vorhanden ist. Am Beispiel von gestern:

    Public Interface IFoo
     Sub Foo()
    End Interface
    
    Public Class Class1
     Implements IFoo
    
     Public Sub Foo() Implements IFoo.Foo
     MsgBox("Foo")
     End Sub
    End Class
    
    ' Anwendung:
    
     Dim o As Object
     Dim t As System.Type
    
     Dim lClass As String = "CreateInstanceAndMethodInfo.Class1"
    
     t = Assembly.GetExecutingAssembly().GetType(lClass)
    
     If t IsNot Nothing Then
     o = Activator.CreateInstance(t)
    
     If TypeOf o Is IFoo Then
     DirectCast(o, IFoo).Foo()
     End If
     End If

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Donnerstag, 1. Juli 2010 07:31
  • Hallo Mario,

    da sich solche Informationen nicht sekündlich ändern,
    sollte man dies bereits vorher erstellen.

    So bieten sich zum Beispiel Generatoren an wie TT4 Templates,
    die die Klassen (vergleichbar mit typisierten DataSets) vorher erzeugen.

    Wobei ich Dir empfehlen würde, Dich mit gängigen ORMs wie
    Entity Framework, NHibernate zu beschäftigen.
    Oder wenn Du meinst, es dynamisch haben zu müssen, siehe z. B. Subsonic

    Ein Selbstbau an der Stelle ist mit einigen Risiken und nicht zu
    unterschätzenden Aufwand verbunden, denn die Tücke liegt
    dort im Detail.

    Gruß Elmar

    Donnerstag, 1. Juli 2010 10:04