Announcement

Collapse
No announcement yet.

klasse aus Assembly laden

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • klasse aus Assembly laden

    moin,

    ich habe foglendes problem:

    ich muss aus einer dll eine klasse laden was ja mit reflections recht einfach ist. nun hatte ich gedacht das folgendes geht:

    Code:
    class A
    {
         public void arbeite()
         {
                //tue was
         }
    }
    
    class B : A
    {
         public void arbeite()
         {
              //tue was anderes
         }
    }
    ich dachte nun das ich die klasse B aus einem assembly laden kann und einem object vom typ A zuweisen kann. genau genommen geht das auch, nur wenn ich "arbeite()" aufrufe wird die methode der klasse A aufgerufen obwohl mir der debugger klar anzeigt, dass das objekt eigentlich von der klasse B ist.
    so in etwa sah das im programm code aus:

    Code:
    Assembly a = Assembly.LoadFile("b.ll")
    Type[] t = a.GetTypes()//ka ob die methode so hies
    A Objekt = (A)a.CreateInstance(t[0].to_string());
    im sinne der polymorphie sollte nun Objekt.arbeite() die methode von B aufrufen was aber wie schon gesagt nicht passiert. Der Typ aus der assembly datei wird in meinem programm auch nicht bekannt sein, dh ich kann auch nicht direkt ein objekt vom typ B erzeugen

    hat jemand eine erklärung und vielleicht aucheine lösung für mein problem?

    mfg
    Zebes

  • #2
    Du musst die passenden Schlüsselworte ergänzen um das gewünschtes polymorphe Verhalten zu bekommen.

    Code:
    class A
    {
         public virtual void arbeite()
         {
                //tue was
         }
    }
    
    class B : A
    {
         public override void arbeite()
         {
              //tue was anderes
         }
    }

    Comment


    • #3
      ohhhhhh man bin ich blöde ^^.

      ok darauf hätte ich auch kommen müssen.

      vielen dank für die schnelle antwort

      mfg
      Zebes

      Comment


      • #4
        Nun zum 2.Teil deines Posts. Einfach das 0.te Element aus der Collection von GetTypes() zu erzeugen ist riskant. Könnte ja alles mögliche sein. Bekommst ja nicht nur Klassen sondern alle Typen und dann auch noch für alle Sichtbarkeiten (also auch private!).

        Ich würde dir empfehlen ein Interface zu erzeuge. In deinem Beispiel
        zum Beispiel so

        Code:
        public interface IArbeite
        {
           public void arbeite();
        }
        Und das von Klasse A und B implementieren lassen.
        Dann kanst du mit einem einfachen Test sauber feststellen ob du den einen gültigen Typ erwischt hast.

        Code:
        Assembly assembly = Assembly.LoadFile("b.ll");
        foreach (Type type in assembly.GetTypes())
        {
           if (type.IsClass && type.IsPublic && (type.GetInterface(typeof(IArbeite).FullName) != null))
             return Activator.CreateInstance(type));
        }

        Comment


        • #5
          ja vielen dank ich werde mir das mal genauer anschauen.
          aber kann ich das denn mit abgeleiteten klassen genau so machen? also es gibt zb eine abstrakte basisklasse und in einer dll befinden sich dann die knkrete abgeleiteten klassen. dann müsste ich doch auch abfragen können welcher basisklasse sie angehören oder? wäre im prinzib der sache mit den interfaces sehr ähnlich

          mfg
          Zebes

          Comment


          • #6
            Also ich muß dazu sagen das ich in c# recht neu bin und vorher hauptsächlich mit c++ gearbeitet hatte. deshalb verstehe ich auch nicht so ganz den vorteil eines interfaces gegenüber einer abstracten klasse, außer um mehrfach vererbung nachzubauen.

            achja was mir gerad enoch einfällt. gibt es einen bestimmten grund warum du die methode der klasse Activator verwendest anstelle der methode die dir die Assembly klasse zur verfügung stellt?

            mfg
            Zebes
            Zuletzt editiert von Zebes; 05.06.2007, 10:09.

            Comment


            • #7
              so gerade hat sich beim laden einer assembly noch ein anderes problem ergeben.

              also kurz zu erklärung vorweg, mein programm ist aufgeteilt in allgemeine komponenten die über einen direkten verweis verwendet werden können, eine hauptkomponente die auch die main-funktion beinhaltet und noch komponenten die dynamisch geladen werden müssen halt aus den assemblys.

              nun wollte ich eine meiner frei verwendbaren komponenten in einer meiner dynamisch geladenen komponenten verwenden. doch sobald ich versuche ein object der freien komponente zu erzeugen wird mir eine exception geworfen in der steht das die assembly der komponente nicht vorhanden sei.

              liegt das jetzt daran das ich versuche im konstruktor eines der objekte zu erzeugen oder hat das andere gründe?

              mfg
              Zebes

              Comment


              • #8
                Zum Thema Interfaces vs. abstrakte Basisklasse hast du Recht, beides funktioniert. Wenn du aber an Erweiterung/Wartung der Software denkst sind Interfaces deutlich flexibler. Durch die abstrakte Basisklasse sind alle gezwungen die eine bestimmte Funktionalität wollen von deiner Basisklasse abzuleiten. Stell dir aber vor es gibt bereits woanders eine Klasse die eigentlich schon alles macht was jemand brauchst er müsste nur noch ein bestimmtes Verhalten ergänzen so das es mit dem Rest deiner Anwendung sprechen kann.
                Diese Klasse bekommst du nie in die Vererbungshierarchie einer abstrakten Klasse.

                In guten Frameworks ist es übrigens üblicherweise so das beides benutzt wird. Es gibt eine abstrakte Basisklasse die ein Interface implementiert. Die abstrakte Basisklasse hält dann teilweise Standardimplementierungen bereit um die Erzeugung weiterer abgeleiteter Klassen zu vereinfachen. Sollte diese Standardimplementierung aber mal nicht passen oder ich habe keine Chance mich in dessen Vererbungshierarchie zu hängen kann ich dann direkt das Interface nehmen und bin nicht gezwungen die Basisklasse anzupassen was eventuell zu Rekompilierung aller Nachfahren zwingt. (Hast du diese Basisklasse verkauft und Kunden habe eigene Ableitungen implementiert hast du dann ein echtes Problem.)

                Ich selber mach das nicht so streng. Aber immer wenn ich bemerke das ich grad eine Typprüfungen auf eine Klasse programmiere höre ich schon immer die leisen Stimmen aus dem Off die flüstern 'Na, sollte das vielleicht ein Interface werden?'.


                gibt es einen bestimmten grund warum du die methode der klasse Activator verwendest anstelle der methode die dir die Assembly klasse zur verfügung stellt?
                Assembly.CreateInstance gibst du den Typnamen(als string) der dann erst in eine Typ aufgelöst werden muß um ihn zu erzeugen. Wenn Assembly.CreatInstance den Typ ermittelt hat ruft es selbst dann Activator.CreateInstance auf um eine Instanz zu erzeugen. Da wir den Typ aber schon haben können wir auch gleich Activator.CreateInstance damit aufrufen.


                Zu deinem letzten Problem müsste ich ein wenig konkreten Code sehen.
                Ist es wirklich so wie ich deine Problembeschreibung verstehe das du eine korrekte Assembly bekommst(Assembly.LoadFile), daraus einen korrekten Typ (Assembly.GetTypes())es dann aber knallt wenn du eine Instanz erzeugen willst(Activator.CreateInstance)?

                Als Schuss ins blaue, vielleicht hat deine Assembly selbst wieder Abhängigkeiten auf andere Assemblies die nicht gefunden werden? Sieh dir am besten nochmal genau die Fehlermeldung an ob wirklich der Typ gemeint ist den du gerade erzeugst oder eine Abhängigkeit.

                Comment


                • #9
                  Zu deinem letzten Problem müsste ich ein wenig konkreten Code sehen.
                  Ist es wirklich so wie ich deine Problembeschreibung verstehe das du eine korrekte Assembly bekommst(Assembly.LoadFile)
                  ja genau das geht einwandfrei

                  , daraus einen korrekten Typ (Assembly.GetTypes())es dann aber knallt wenn du eine Instanz erzeugen willst(Activator.CreateInstance)?
                  genua so.

                  Als Schuss ins blaue, vielleicht hat deine Assembly selbst wieder Abhängigkeiten auf andere Assemblies die nicht gefunden werden? Sieh dir am besten nochmal genau die Fehlermeldung an ob wirklich der Typ gemeint ist den du gerade erzeugst oder eine Abhängigkeit.
                  genua das sagt die exception die ich bekomme. allerdings ist diese dll direkt als verweis eingetragen habe jetzt gerade keinen konkreten code hier aber das würde im prinziep so aussehen.

                  das hier wäre die über all einsetzbare komponente:
                  Code:
                  public class frei
                  {
                      public frei()
                      {
                           
                      }
                  
                       public arbeite()
                       {
                              //tue was
                       }
                  }
                  das wäre die klasse die hinterher dynamisch geladen werden müßte:
                  public class dynclass
                  {
                  private frei item

                  public dynclass()
                  {
                  item = new frei();

                  item.arbeite();
                  }
                  }
                  so und in meiner haupt klasse wird dynclass dann dynamisch geladen

                  Code:
                  //.....
                  Assembly a = Assembly.LoadFile(dynclass.dll);
                  Type[] t = a.GetExportedTypes();
                  
                  foreach(Type ExportedType in i)
                  {
                      if(ExportedType.IsClass && ExportedType.Fullname == GewünschteKlasse)
                      {
                            a.CreateInstance(ExportedType.Fullname, false, /*halt noch die übergabe parameter*/)
                       }
                  }
                  //.....
                  und bei createinstance krachts. neme ich aber das erzeugen eines Objektes der klasse "Frei" also die anweisung mit new raus, so habe ich keine probleme.

                  allerdings sollte die klasse "Frei" statisch beim kompilieren "gelinkt" werden da ich in meinem VS die komponente unter Verweise hinzu gefügt habe. oder gibt es bei dynamisch geladenen assemblys da eine ausnahme?

                  mfg
                  zebes
                  Zuletzt editiert von Zebes; 05.06.2007, 20:06.

                  Comment


                  • #10
                    Äh. Ich glaube ich habe deine Beschreibung nicht verstanden.
                    Soll nun dynclass, frei oder beides aus der dynamisch geladenen Assembly geholt werden? Und wofür ist dynclass?

                    Noch so ein Schuss ins blaue. Wo liegen die Assemblies relativ zu deiner Anwendung(exe)?
                    Wenn dynclass, frei und deine Anwendung sich in 3 verschiedenen Assemblies befinden liegen alle 3 im selben Verzeichnis? Also wenn du das debuggst sind dann alle im bin/debug Ordner?

                    Comment


                    • #11
                      also dynclass steht für eine xbelibige klasse die ich dynamisch zu laufzeit laden will die klasse frei ist einfach eine kompponente die ich statisch zu dynclass hinzu füge zb könnte das etwas sein um mathematische berechnungen durchzu führen oder die socket klasse.

                      hmm auswendig weis ich das jetzt nicht genau wo die liegen aber das sollte kein problem sein, da der kompiler eine fehlende ddl doch eigentlich schon zur kompiel zeit festellen müsste. oder muss eine statisch gelinkte dll auch im ordner der main.exe liegen obwohl sie aus einer ganz anderen dll aufgerufen wird?

                      mfg
                      Zebes

                      Comment


                      • #12
                        Erstmal da wird nichts gelinkt. Eine Referenz bleibt eine unabhängige Assembly.


                        Das er beim Kompilieren seine Referenzen finden muß ist natürlich richtig.
                        Aber (ich spekuliere jetzt hier) vermutlich kompilierst du zuerst dein Projekt das dynclass und frei enthält. Dann befindet sich die entsprechende dll und die Abhängigkeiten im bin/debug Ordner dieses Projekts. (Z.B. C:/dynclass/bin/debug) Dann kompilierst du deine Anwendung wodurch die exe und dessen Abhängigkeiten im bin/debug Ordner dieses Projektes liegen.
                        (z.B. C:/Anwendung/bin/debug).

                        Wenn nun die Anwendung dynclass dynamisch lädt(Assembly.LoadFile) machst du das aus irgendeinem Ordner(C:/dynclass/bin/debug). Wenn auch noch einen Typ aus dieser Assembly erzeugt wird müssen die abhängigen Assemblies dieser Assembly mitgeladen werden. Diese werden im aktuellen Ordner gesucht in dem die Anwendung läuft (C:/Anwendung/bin/debug) und NET typisch noch im GAC. Aber nicht im Ordner aus dem du die Assembly geladen hast(C:/dynclass/bin/debug).

                        Comment


                        • #13
                          also mit "gelinkt" war einfach das hinzufügen eines verweises gemeint. ^^

                          aber du hattest recht, es war ein problem mit den dlls.

                          vielen dank für deine hilfe.

                          jetzt ist nur doof das ich drauf achten muss das ich verweise in dynamisch geladenen dll in das hauptverzeichnis lege oder gibt es dazu eine möglichkeit dies zu umgehen das die information an die dynamisch geladene dll gebunden wird. also das die dynamisch geladene klasse ihre komponenten im prinzip selbst mit bringt. weil wenn man das von hand machen muss so bekommt man doch bei größeren komponenten ein problem wenn ich immer drauf achten muss das auch ja alle abhängigkeiten aufgelöst werden.

                          mfg
                          Zebes

                          Comment


                          • #14
                            Nun fürs richtige Deployment sollte das dein Installbuilder automatisch draufhaben(ein VS Setupprojekt macht das zum Beispiel) die Abhängigkeiten zusammenzusuchen.

                            Wenn es dir erstmal nur ums entwickeln geht könntest du einfach das Ausgabeverzeichnis deiner Projekte auf einen zentralen Ordner umbiegen.
                            Kannst du in Properties/Build/OutputPath(sollte in einem deutschen VS ähnlich heißen) deiner Projekte umstellen. (Vielleicht gleich eine neue Konfiguration dafür anlegen um die Standardkonfigurationen Build/Release nicht ändern zu müssen).

                            Ein weitere Lösung wäre ILMerge damit kannst du verschiedene Assemblies zu einer zusammenfassen. Ist aber in deinem Fall vermutlich nicht möglich/hilfreich da falls du im Hauptprogramm und in den weiteren Assemblies dieselben Abhängigkeiten hast und in beiden Teilen jeweils eine Version dieser Assembly hinzumergst hast du auf einmal dieselbe Assembly mehrmals in deiner Anwendung. Das läuft auf Probleme hinaus.

                            Comment


                            • #15
                              noch mal vielen dank für deine hilfe

                              mfg
                              Zebes

                              Comment

                              Working...
                              X