Vererbungs Problem

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von Blitzbirnep.

    Vererbungs Problem

    Hallo liebe Community,

    Ich stehe wohl wieder einmal auf dem schlauch, ich hab mir ein neues Projekt zur Brust genommen und habe ein Problem das für mich äußerst unlogisch erscheint, wahrscheinlich übersehe ich da was hoffentlich könnt ihr mir helfen also:

    Ich habe eine HauptForm und eine Hauptdll und eine Subdll

    Die HauptForm lädt dynamisch die Hauptdll diese wiederum dynamisch die Subdll, soweit funktioniert alles super.

    Jetzt muss ich aber aus der Subdll Daten (String) in die HauptForm bekommen, um dies zu bewerkstelligen habe ich eine Form geschrieben:

    Spoiler anzeigen


    VB.NET-Quellcode

    1. Public Class CenterForm
    2. Inherits Windows.Forms.Form
    3. Public Event OnBeChanged(ByVal NewBe As Object)
    4. Public Sub ChangeBe(ByVal ChangedBe As Object)
    5. RaiseEvent OnBeChanged(ChangedBe)
    6. End Sub
    7. End Class




    der Form1 die eigenschaften von meiner Form vererbt.

    Spoiler anzeigen


    VB.NET-Quellcode

    1. Public Class Form1
    2. Inherits CenterForm
    3. '... Hier passiert einiges z.B. wird die Hauptdll hier geladen etc. blabla
    4. End Class




    mein Gedanke dabei war dass, ich die Hauptform als Parameter durch die dlls reiche bis hin zu meiner Subdll, dort ereicht sie die Funktion wo ich die Daten rüberschicken muss, da führt die Funktion der Subdll, den folgenden Befehl aus,

    VB.NET-Quellcode

    1. m_form.ChangeBe("O") 'm_form ist in dieser Klasse mein Attribut indem ich die Hauptform gespeichert hab.

    Nach diesem Befehl wird das Event OnBeChanged ausgelöst (in meiner Hauptform) und schwups hab ich den String da wo ich ihn haben wollte.

    So der Wurm steckt nun darin dass, eine Fehlermeldung bei der übergabe meiner Parameter vorkommt undzwar genau an der stelle wo die Parameter von der Hauptform in die Hauptdll übergeben werden.

    Spoiler anzeigen


    VB.NET-Quellcode

    1. Private Sub LoadMainDll()
    2. Try
    3. sparam(0) = sgamepfad
    4. sparam(1) = Me
    5. sparam(2) = SelectGame.statusinfo.cName
    6. sloadassambly = Assembly.LoadFile(Environment.CurrentDirectory & "\LoadAssambly.dll")
    7. Dim typs() As Type = sloadassambly.GetTypesFor Each typ As Type In typs
    8. If typ.IsClass = True And typ.IsPublic = True Then
    9. sobj = sloadassambly.CreateInstance(typ.FullName)
    10. Dim m As MethodInfo() = sobj.GetType.GetMethods
    11. For Each mobj As MethodInfo In m
    12. If mobj.Name = "LoadGame" Then
    13. mobj.Invoke(sobj, sparam)'Hier!!! :(
    14. End If
    15. Next
    16. End If
    17. Next
    18. Catch ex As Exception
    19. MsgBox("Fehler beim Laden der " & Environment.CurrentDirectory & "\LoadAssambly.dll" & vbNewLine & ex.Message)
    20. End Try
    21. End Sub





    Die Fehlermeldung lautet: Das Objekt mit dem Typ "BlitzCenter.Form1" kann nicht in den Typ "LoadAssambly.CenterForm" konvertiert werden.

    BlitzCenter ist das Projekt mit der Hauptform.

    LoadAssably ist das Projekt mit der Hauptdll.

    Schonmal danke das ihr euch das überhaupt durchgelesen habt :thumbsup: ;)
    Oh, oh - jetzt kommen 4 versch. Gedanken - bitte nicht sich nur mit einem davon auseinandersetzen:

    1. ich denke: falsches Anwendungs-Design. Das Form sollte eine Instanz deiner Klasse enthalten, nicht umgekehrt. Wenn die Klasse am Form manipulieren will, dann soll sie ein Event feuern, welches im Form behandelt wird.
      gugge VeryBasics
      vlt. würdedas auch gleich deine InvalidCast-Exception reparieren.

    2. Ah - InvalidCast-Exception! Wird in meim neuesten tut erwähnt (was leider noch nicht on ist): Da klingelt bei mir immer gleich, nach Option Strict On! zu fragen.
      Weil normal müsste bereits der Compiler rummeckern, ohne jeden Testlauf.

    3. Ich vermute, inne Haupt-Dll hast du eine gleichnamige Klasse wie inne SubDll, aber nur weilse gleich benamt sind, ists nicht dieselbe Klasse.

    4. Dann erwähnst du noch den LoadAssembly-Zirkus - das ist doch, wenn man PlugIns versucht, oder?

      Na, fiel Fergnügen damit - PlugIn bedeutet: eine Dll. wird verwendet, über die garnix bekannt ist. (Und von Klassen daraus kann man selbstverständlich auch nix erben)
    Danke für die schnelle antwort ;)

    Also erstmal ja das ist nach einem Pluginsystem aufgebaut, und zweitens ja das hab ich auch gemerkt, deswegen hab ich ja in allen drei dll datein die selbe klasse reinkopiert (Center Form), zumindest dachte ich das es die selbe ist, du meinst ja iwi (4.) das ist nicht die selbe? wie meinst du das?

    Mit option strict hab ich jetzt gefühlte 100 fehler behoben, aber da es ja eine dll ist wird der fehler es nicht sein, wenn er es überhaupt ist. :/

    Deinen ersten punkt verstehe ich noch nicht so richtig, könntest du den nochmal erklären bitte?



    Edit:

    Was passiert eigentlich wenn ich eine klasse x der klasse y vererbe und neue sachen hinzufüge, wenn ich jetzt die klasse y in eine variable von klasse x speichere. gehen dann die neune sachen verloren?



    Edit2:

    Ich glaube ich hab was gefundne undzwar, ich erstelle in meiner hauptform eine klasse und den selben code kopiere ich in meine dll, die vehlermeldung die angezeigt wird ist : xyz.Klasse kann nicht in abc.Klasse konvertiert werden. :cursing:

    Aber die beiden sind doch identisch vom code her??? was mache ich falsch??? ?(

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Blitzbirnep“ ()

    1. Blitzbirnep schrieb:

      Deinen ersten punkt verstehe ich noch nicht so richtig, könntest du den nochmal erklären bitte?
      Der Punkt ist ausführlich im gegebenen Link erklärt - bitte frage präziser, denn ich will das verlinkte hier jetzt nicht komplett wiederholen.

    2. Blitzbirnep schrieb:

      Was passiert eigentlich wenn ich eine klasse x der klasse y vererbe und neue sachen hinzufüge, wenn ich jetzt die klasse y in eine variable von klasse x speichere. gehen dann die neune sachen verloren?
      auch unpräzise: Erbt nun Y von X, oder X von Y, und fügst du an X oder an Y neue Sachen zu?
      Auch hier ist die Frage zu umfassend, als dass ich sie hier in der notwendigen Ausführlichkeit behandeln könnte: dieses Buch Lesen Am im genannten Buch vermittelten Vererbungs-KnowHow kommst du so oder so nicht vorbei, wenn du proggen willst.

    3. Blitzbirnep schrieb:

      ich erstelle in meiner hauptform eine klasse und den selben code kopiere ich in meine dll, die vehlermeldung die angezeigt wird ist : xyz.Klasse kann nicht in abc.Klasse konvertiert werden. :cursing:

      Aber die beiden sind doch identisch vom code her?
      Das sagte ich bereits in post#2-pkt#3: Wenn du in 2 Dlls 2 Klassen hast, sind diese Klassen mitnichten identisch, auch wenn derselbe Code hineinkopiert ist. Eineiige Zwillinge sind ja auch nicht eine Person, sondern zwei.
      Damit führst du übrigens dein PlugIn-System ad absurdum, denn wenn du den Code nun eh in der Haupt-Dll hast, dann kannste das PlugIn ja auch weglassen.
      (wie gesagt: ich halte aus prinzipiellen Gründen nicht viel von PlugIn-Systemen)

      ErfinderDesRades schrieb:

      PlugIn bedeutet: eine Dll. wird verwendet, über die garnix bekannt ist. (Und von Klassen daraus kann man selbstverständlich auch nix erben - sie sind ja garnet bekannt)


    4. Vorschlag für eine schrittweise Entwicklungs-Strategie:
      • Vergiß erstmal das PlugIn-Theater, und bring erstmal eine normale App ühaupt ans laufen
      • teile meinetwegen die App auf in mehrere Projekte, die in einer Solution zusammengebunden sind
      • Wenndes dir dann noch unbedingt antun willst, versuch, die ausgelagerten Projekte ganz herauszutrennen, und dann dynamisch als PlugIn zu laden.
        fiel Fergnügen damit ;)
      • PS: Immer schön Backup machen ;)

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ErfinderDesRades“ ()

    1. Wie will ich denn ein Event "feuern"?

    Ja das hab ich jetzt auch gemacht eine Klasse geschrieben die aussieht wie im obeigen post "center Form" und die dann als instanz in meine form übergeben, dort wird er einmal mit new instanziert und nachdem durch die dlls, als parameter geschleust.

    2. also Die Klasse SchönerApfel erbt von der KlasseApfel, alle eigenschaften, methoden, etc. erhält zusätzlich die methode "schönzusein",

    So jetzt speichere ich den SchönenApfel (wurde vorher instanziert) in dei Variable "Dim x As Apfel = SchönerApfel", meine frage war jetzt hat x jetzt noch die methode "schönzusein"?

    3. Ja das hab ich jetzt auch bemerkt, dein beispiel ist gut gewählt :thumbup: , dass wusste ich aber vorher noch nicht woran liegt das denn?

    Wie gesagt ich hab das so gelöst das ich eine dritte dll, den zwei dlls verwiesen hab, und in dieser dritten dll steht nun die Klasse "CnterForm" die ich dann aus namensgründen in "Vermittler" umgeändert hab und die vererbung von Windows.Forms.Form entfernt hab.

    4. Ja du hast recht, das war mir bewust, mein ziel ist es jedoch nicht dass andere anwender, plugins schreibn könne, mein Ziel ist es. Ok ich erkläre mein Projekt:

    Als erstes hab ich ein einfaches spiel programmiert. Welches man an einem computer zu zweit spielen kann. Das hat meinen Freunden so seher gefallen das sie einen Multiplayer wollten, dieser sollte aber nicht lokal sein, d.h. zwei computer.

    So, dann hab ich mich an die TCP programmierung gesetzt, ein paar tuts gelesen, und als übung einen chat geschrieben, dieser lief einwandfrei in den computerräumen an meiner schule.

    Mit dem nötigen wissen hab ich jetzt ein Programm geschrieben, was dieses spiel (ebenfalls in form einer dll, diese dll ist meine subdll die ich vorher beschrieben hab) lädt und wiedergibt.

    Damit ich jetzt nicht für jedes spiel das ich erstellen werde eine neu verbindungsprogramm erstellen muss hab ich mir gedacht ich mach das in der art von einem Pluginsystem, sodass ich spiele immer nach der gleichen strucktur programmiere und die dan durch dieses programm verbunden werden können. Deshalb steht z.B. der Code zum erstellen der GUI ebenfalls in der spiele dll drin.

    So das ist mein projekt, wie gesagt ich hab das problem jetzt gelöst, die spieler können sich jetzt untereinander verbinden und der server empfängt die daten vom klienten und umgekehrt, das letzte was ich jetzt machen muss ist die auswertung von den daten, wenn du lust hast kann ich ja mal mein projekt hochladen und du kannst es dir anschauen, ich will aber keine umstände machen ist ja schon nett das du mir hier hilfst :thumbsup:
    1. Du schreibst in die Dll sowas wie:

    VB.NET-Quellcode

    1. Public Class DeinKlassenNameOderSo
    2. Public Event DeinEvent As Action
    3. 'Optional:
    4. Public Event DeinEvent As Action(Of Typ, Typ, Typ, ...)
    5. 'um Parameter angeben zu können.
    6. Private Sub Foo()
    7. RaiseEvent DeinEvent
    8. 'Bzw. wenn Du Parameter verwendet hast:
    9. RaiseEvent DeinEvent(Bar, ...)
    10. End Sub
    11. End Class

    So in etwa kann man sich das vorstellen.
    In deinem Hauptprojekt wird dann irgendwas stehen wie:

    VB.NET-Quellcode

    1. Sub Bla()
    2. Dim Test As New DeinDllNameOderSo.DeinKlassenNameOderSo
    3. AddHandler Test.DeinEvent, AddressOf ZielSub
    4. End Sub


    2.
    Man nehme Formen:

    VB.NET-Quellcode

    1. Class Shape
    2. Public PositionX As Integer
    3. Public PositionY As Integer
    4. Public Sub New(ByVal NewX As Integer, ByVal NewY As Integer)
    5. PositionX = NewX
    6. PositionY = NewY
    7. End Sub
    8. End Class


    Davon leite man Rechtecke und Kreise ab:

    VB.NET-Quellcode

    1. Class Rectangle
    2. Inherits Shape
    3. Public Width As Integer
    4. Public Height As Integer
    5. Public Sub New(ByVal NewX As Integer, ByVal NewY As Integer, ByVal NewWidth As Integer, ByVal NewHeight As Integer)
    6. PositionX = NewX
    7. PositionY = NewY
    8. Width = NewWidth
    9. Height = NewHeight
    10. End Sub
    11. End Class
    12. Class Circle
    13. Inherits Shape
    14. Public Radius As Integer
    15. Public Sub New(ByVal NewX As Integer, ByVal NewY As Integer, ByVal NewRadius As Integer)
    16. PositionX = NewX
    17. PositionY = NewY
    18. Radius = NewRadius
    19. End Sub
    20. End Class


    Wir können also sagen:

    VB.NET-Quellcode

    1. Dim Shapes As New List(Of Shape)
    2. Sub Foo()
    3. Shapes.Add(New Shape(1, 2))
    4. Shapes.Add(New Rectangle(1, 2, 3, 4))
    5. Shapes.Add(New Circle(1, 2, 3))
    6. End Sub


    Eines haben alle gemeinsam:
    PositionX und PositionY
    Das heißt also wir können die Position jedes Elementes problemlos herausfinden:

    VB.NET-Quellcode

    1. For Each i As Shape In Shapes
    2. SubForShape(i.PositionX, i.PositionY)
    3. Next


    Schwieriger wird es, wenn man z.B. den Radius herausfinden möchte. Denn nicht jedes Shape hat einen Radius (nur die Shapes, die Circles sind).
    Darum muss man zuerst herausfinden, von welchem Typ das Shape ist und anhand dessen was machen:

    VB.NET-Quellcode

    1. For Each i As Shape In Shapes
    2. If TypeOf i Is Circle Then
    3. SubForCircle(i.PositionX, i.PositionY, i.Radius)
    4. ElseIf TypeOf i Is Rectangle Then
    5. SubForRectangle(i.PositionX, i.PositionY, i.Width, i.Height)
    6. Else
    7. SubForShape(i.PositionX, i.PositionY)
    8. End If
    9. Next

    Tja, warum geht das nicht? Weil der Compiler ja noch nicht weiß ob i jetzt nur ein Shape ist oder doch ein Rectangle.
    Darum muss gecastet werden:

    VB.NET-Quellcode

    1. For Each i As Shape In Shapes
    2. If TypeOf i Is Circle Then
    3. Dim ThaItem As Circle = DirectCast(i, Circle)
    4. SubForCircle(ThaItem.PositionX, ThaItem.PositionY, ThaItem.Radius)
    5. ElseIf TypeOf i Is Rectangle Then
    6. Dim ThaItem As Rectangle = DirectCast(i, Rectangle)
    7. SubForRectangle(ThaItem.PositionX, ThaItem.PositionY, ThaItem.Width, ThaItem.Height)
    8. Else
    9. SubForShape(i.PositionX, i.PositionY)
    10. End If
    11. Next

    Und warum muss bei SubForShape(i.PositionX, i.PositionY) nicht gecastet werden? Weil jedes i 1. bereits ein Shape ist und 2. mindestens ein Shape ist. Ich weiß, das hört sich jetzt doof an, aber es ist so: Jedes von Shape erbende Objekt hat eine PositionX und PositionY Eigenschaft.

    Wichtig: Dieses Beispiel ist nur als Verdeutlichung gedacht! Es hat nicht wirlich einen parktischen Nutzen.

    3.
    Das liegt ganz einfach daran, dass niemand (außer Du) weiß, dass in der Dll effektiv der selbe Code steht wie im Hauptprojekt.
    Wie die Fehlermeldung schon sagt: abc.Bla kann nicht in xyz.Bla umgewandelt werden.
    Du siehst: Sie sind nicht gleich.

    3.2. und 4.
    Bei solchen Spielen kommen sogenannte Interfaces ins Spiel.
    Das Ganze läuft so ab, dass Du im Hauptprojekt

    VB.NET-Quellcode

    1. Dim DasSpiel As DllName.InterfaceName
    2. Sub LadeSpielAusDll()
    3. DasSpiel = 'Keine Ahnung wie das genau geht. Damit habe ich noch nie gearbeitet.
    4. End Sub
    5. 'Beispiel für Verwendung:
    6. Sub DrawGraphics(...) Handles Me.Paint
    7. 'Die DrawGraphicsOn Sub zeichnet z.B. die Grafiken des Spiels auf den Bildschirm, indem man ihr das Graphics Objekt übergibt.
    8. DasSpiel.DrawGraphicsOn(e.Graphics)
    9. End Sub


    Dieses Sytem ist allerdings für Dein Vorhaben nicht so gut geeignet. Ich gehe jetzt erst mal Abendessen und nachher melde ich mich wieder.
    Dann erkläre ich wie es einfacher geht.


    Edit:
    So.
    Ich erkläre mal wie es einfacher geht. Drehe die Ordnung um. Du hast Dein Spiel und diesem Spiel gibst Du die Dll, die das Senden/Empfangen der Daten verarbeitet.

    Baue Deine Dll nach diesem Schema um:

    VB.NET-Quellcode

    1. Public Class TCPDingens
    2. 'TCP Daten bezeichnet einen Typ, in dem alle nötigen Daten enthalten sind, die Du senden musst.
    3. 'Ich kenne mich mit TCP Verbindungen zu wenig aus um genaueres sagen zu können.
    4. Public Event DataReveived As Action(Of TCPDaten)
    5. Public Event LostConnection As Action
    6. Public Sub SendData(ByVal Data As TCPDaten)
    7. 'Dein Code zum Senden der Daten
    8. End Sub
    9. Private Sub Connection_DataReceived(...) 'Handles irgendwas
    10. 'Irgendwoher weißt Du, dass Du Daten bekommen hast
    11. RaiseEvent DataReceived(New TCPDaten(...)) 'Die nötigen Daten dem Event mitgeben
    12. End Sub
    13. Private Sub Connection_LostConnection() 'Handles irgendwas
    14. 'Und irgendwoher weißt Du, dass die Verbindung abgerissen ist.
    15. RaiseEvent LostConnection
    16. End Sub
    17. End Class


    Dann importierst Du die Dll in Dein Hauptprojekt (und auch in andere Spiele) und verwendest diese um die Daten zu senden und zu empfangen.
    Importieren so:


    Das hat auch erhebliche Vorteile was das Debugging betrifft. Denn externe Dlls kann man zwar debuggen (wenn es sich um eine im VS erstellte Dll handelt), aber es ist umständlicher Änderungen vorzunehmen. Und ich denke mal ein Spiel wird komplizierter und benötigt das Debugging dringender als die Dll.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    @Niko

    Vielen dank für deine ausführliche hilfe!! das war wirklich super!

    Ich hab jetzt mein projekt nachdem auch etwas umgestalltet, die haupt dll die meine spiele lädit ist im grunde überflüssig deshalb hab ich die rausgeschmissen jetzt ist das ganze um einiges einfacher geworden, es gibt die hauptform (connector) und meine spiele die nach der selben struktur (also selbe funktions, methoden namen haben, sodass sie in meine hauptform passen) am anfang wähle ich halt aus welche dll geladen werden soll und dann wird das gemacht. !

    Nochmal ein dickes Dankeschön! :thumbsup: :thumbsup: ihr seit einfach die besten!