Parameter in Abhängigkeit von Enumeration

  • VB.NET

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von FreakJNS.

    Parameter in Abhängigkeit von Enumeration

    Hallo,

    ich wollte mal fragen, ob es möglich ist, verschiedene Parameter in Abhängigkeit von einer Enumeration zur Auswahl auszugeben oder ob ihr eine ähnliche Methode kennt.

    VB.NET-Quellcode

    1. Enum Enume
    2. a = 0
    3. b = 1
    4. c = 2
    5. End Enum
    6. Public Function SetParameters(ByVal Option as Enume)
    7. Select Case Option
    8. Case a
    9. (...)
    10. Case b
    11. (...)
    12. End Function


    Wenn man die Funktion SetParameters aufruft, sollen dann, je nachdem welches Element als "Option" angegeben wird, verschiedene Parameter zur Auswahl gestellt werden. So etwas in der Art wie

    VB.NET-Quellcode

    1. Private Sub Test()
    2. SetParameters(a)(test1, test2)
    3. SetParameters(b)(test1)
    4. End Sub


    Wobei, nachdem SetParameters(...) aufgerufen wurde, auch die möglichen Parameter angezeigt werden sollen.

    Gibt es soetwas, oder kennt ihr eine ähnliche Methode?

    Hintergrund ist, dass ich in einem Programm Optionen in einer Klasse bei der Erstellung von dieser angeben kann, die als Enumeration angezeigt werden. Die verschiedenen Optionen benötigen aber unterschiedliche Parameter.

    Danke,

    Thilo

    ~blaze~ schrieb:

    Hi
    das geht soweit nur bei Generika:

    VB.NET-Quellcode

    1. Public Function MyFunction(Of T)(ByVal someArgs As MyEnumeration) As T


    T ist dann quasi ein Platzhalter für den Typen. Über Enumerationen geht es demnach nicht. Was möchtest du denn genau machen?

    Gruß
    ~blaze~
    Das ist ja schonmal was. Würde dann so aussehen

    VB.NET-Quellcode

    1. SetParameters(Of Option1)(Arg1, Arg2)
    2. SetParameters(Of Option2)(Arg3, Arg4)


    Das ist schon das, was ich wollte. Nur muss ich jetzt für jede Option eine Klasse erstellen (in dem Fall Option1, Option2). Geht es noch einfacher?
    Also was ich genau machen möchte: Eine neue Klasse wird erstellt, in dieser wird im Constructor aus einer Enumeration ausgewählt. Später in der Klasse werden in Abhängigkeit von dieser Auswahl verschiedene Funktionen ausgeführt, die auch verschiedene Parameterangaben brauchen. Diese möchte ich nun möglichst einfach angeben können.
    Was ich ganz genau machen möchte, das bringt nichts, das zu schreiben. Geht um evolutionäre Algorithmen. Ich möchte die Klassen dafür nur so handhabbar wie möglich für den Nutzer machen, da ich diese später auch veröffentlichen möchte.

    @Sonne: Das war nur ein Beispiel. So ungefähr wollte ich die Optionen festlegen können.
    Mir ging es um die Frage, was du damit erreichen willst. Ich verstehe immer noch nicht, was du eigentlich willst. Warum kannst du den Enum-Parameter nicht im Konstruktor übergeben und intern abspeichern und in Abhängigkeit davon später die aufgerufene Funktion auf interne Funktionen umleiten?
    @Thilo87: Ich denke mal, dass Dir was ganz simples vorschwebt, aber Du nicht in der Lage bist, es einfach zu formulieren.
    Male mal 2 Beispiel-Abläufe mit verschiedenen Parametern auf.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Okay, dann versuche ich es nochmal genauer zu beschreiben.

    @Blaze: Deine Lösung wäre gut, aber sie funktioniert leider nicht, wenn die Signaturen von verschiedenen Funktionen übereinstimmen, musste ich leider feststellen.

    Also ich habe eine Klasse Population_Integer. Wenn diese erstellt wird, sieht der Constructor folgendermaßen aus:

    VB.NET-Quellcode

    1. Public Sub New(ByVal Total_Population As Integer,
    2. ByVal RangeMinimum As Integer,
    3. ByVal RangeMaximum As Integer,
    4. ByVal Mutationrate As Double,
    5. ByVal Chainlength As Integer,
    6. ByRef Fitnessfunction As Genotype_Integer.FitnessfunctionDelegate,
    7. Optional ByVal MutationType As MutationTypes = MutationTypes.Random_Resetting,
    8. Optional ByVal CrossoverType As CrossoverTypes = CrossoverTypes.One_Point,
    9. Optional ByVal SelectionType As SelectionTypes = SelectionTypes.Rangbased,
    10. Optional ByVal ReproductionType As ReproductionTypes = ReproductionTypes.Steady_State_Replace_Worst)
    11. _MutationType = MutationType
    12. (...)
    13. End Sub


    Dort können für z.B. MutationType aus der Enumeration MutationTypes verschiedene ausgewählt werden

    VB.NET-Quellcode

    1. Enum MutationTypes
    2. Random_Resetting = 0
    3. Creep_Mutation = 1
    4. Swap = 2
    5. Insert = 3
    6. Reflect = 4
    7. Scramble = 5
    8. Displace = 6
    9. End Enum


    Später in der Klasse "Population_Integer" wird eine Prozedur aufgerufen.

    VB.NET-Quellcode

    1. Public Sub StepForward()
    2. (...)
    3. Select Case _MutationType
    4. Case MutationTypes.Insert
    5. ' alle unmutierten Kinder mutieren und der Liste der mutierten Kinder hinzufügen
    6. For i As Integer = 0 To UnmutatedChilds.Count - 1
    7. MutatedChilds.Add(UnmutatedChilds(i).Mutation_Insert(_Mutationrate, 2))
    8. Next
    9. Case MutationTypes.Swap
    10. ' alle unmutierten Kinder mutieren und der Liste der mutierten Kinder hinzufügen
    11. For i As Integer = 0 To UnmutatedChilds.Count - 1
    12. MutatedChilds.Add(UnmutatedChilds(i).Mutation_Swap(_Mutationrate, 3))
    13. Next
    14. Case MutationTypes.Creep_Mutation
    15. ' alle unmutierten Kinder mutieren und der Liste der mutierten Kinder hinzufügen
    16. For i As Integer = 0 To UnmutatedChilds.Count - 1
    17. MutatedChilds.Add(UnmutatedChilds(i).Mutation_Creep(_Mutationrate, 0, 1.0))
    18. Next
    19. (...)
    20. End Select
    21. (...)
    22. End Sub


    Dort sieht man, dass die verschiedenen Funktionen Mutation_Insert, Mutation_Swap, Mutation_Creep verschiedene Argumente benötigen. Einzig _Mutationrate ist allen gleich.
    Die Funktionen werden aufgerufen, je nachdem, welches Element man für MutationType im Constructor angegeben hat. Die Frage ist nun, wie man möglichst einfach die Argumente von außerhalb der Klasse "Population_Integer" angeben kann.

    Da wäre die Methode von Blaze ganz gut, aber sie funktioniert leider nicht ganz, wegen der gleichen Signaturen:

    VB.NET-Quellcode

    1. Private _Mutation_Creep_Properties As New Mutation_Creep_Properties
    2. Private Class Mutation_Creep_Properties
    3. Public Minimal_Alteration As Double = 0.0
    4. Public Maximal_Alteration As Double = 2.0
    5. End Class
    6. Public Sub SetParameters(Of Mutation_Creep_Properties)(ByVal Minimal_Alteration As Double, ByVal Maximal_Alteration As Double)
    7. _Mutation_Creep_Properties.Minimal_Alteration = Minimal_Alteration
    8. _Mutation_Creep_Properties.Maximal_Alteration = Maximal_Alteration
    9. End Sub
    10. Private _Mutation_Swap_Properties As New Mutation_Swap_Properties
    11. Private Class Mutation_Swap_Properties
    12. Public n As Integer = 1
    13. End Class
    14. Public Sub SetParameters(Of Mutation_Swap_Properties)(ByVal n As Integer)
    15. _Mutation_Swap_Properties.n = n
    16. End Sub
    17. Private _Mutation_Insert_Properties As New Mutation_Insert_Properties
    18. Private Class Mutation_Insert_Properties
    19. Public n As Integer = 2
    20. End Class
    21. Public Sub SetParameters(Of Mutation_Insert_Properties)(ByVal n As Integer)
    22. _Mutation_Insert_Properties.n = n
    23. End Sub


    Damit könnten die Eigenschaften von außen mit

    VB.NET-Quellcode

    1. Dim P as new Population_Integer(...)
    2. P.SetParameters(Of Mutation_Creep_Properties)(2.0, 5.0)
    3. P.SetParameters(...)


    angegeben werden, nur besitzen SetParameters(Of Mutation_Insert_Properties)(...) und SetParameters(Of Mutation_Swap_Properties)(...) dieselben Signaturen, deswegen gibt der Compiler einen Fehler aus.
    Ich hoffe, jetzt kann jemand helfen.

    Danke :P

    Thilo87 schrieb:

    Die Frage ist nun, wie man möglichst einfach die Argumente von außerhalb der Klasse "Population_Integer" angeben kann.

    Welche denn? Diese in Klammern?

    Thilo87 schrieb:

    UnmutatedChilds(i).Mutation_Insert(_Mutationrate, 2)


    Wo kommen die denn überhaupt her und warum kannst du sie nicht direkt übergeben?

    Und weiter: du hast mehrmals 2 Parameter, einmal 3 Parameter. Warum kannst du deiner Sub nicht 2 Parameter (einen optional) übergeben und die an der richtigen Stelle im Case einsetzen? Die _Mutationrate ist ja intern

    VB.NET-Quellcode

    1. Public Sub StepForward(ByVal par1 As Integer, optional ByVal par2 as Double = 0.0)
    2. (...)
    3. Select Case _MutationType
    4. Case MutationTypes.Insert
    5. ' alle unmutierten Kinder mutieren und der Liste der mutierten Kinder hinzufügen
    6. For i As Integer = 0 To UnmutatedChilds.Count - 1
    7. MutatedChilds.Add(UnmutatedChilds(i).Mutation_Insert(_Mutationrate, par1))
    8. Next
    9. Case MutationTypes.Swap
    10. ' alle unmutierten Kinder mutieren und der Liste der mutierten Kinder hinzufügen
    11. For i As Integer = 0 To UnmutatedChilds.Count - 1
    12. MutatedChilds.Add(UnmutatedChilds(i).Mutation_Swap(_Mutationrate, par1))
    13. Next
    14. Case MutationTypes.Creep_Mutation
    15. ' alle unmutierten Kinder mutieren und der Liste der mutierten Kinder hinzufügen
    16. For i As Integer = 0 To UnmutatedChilds.Count - 1
    17. MutatedChilds.Add(UnmutatedChilds(i).Mutation_Creep(_Mutationrate, par1, par2))
    18. Next
    19. (...)
    20. End Select
    21. (...)
    22. End Sub



    Ich verstehe immer noch nicht, warum du alles so kompliziert machst.

    Und deinen zweiten Codeabschnitt habe ich gar nicht verstanden, ich hoffe, es ging den anderen anders. Ich sehe immer noch keinen Sinn in solchen Verrenkungen...

    Thilo87 schrieb:

    Wenn diese erstellt wird, sieht der Constructor folgendermaßen aus:
    Sehr suboptimal.
    Mach da sehr viele Parameter weniger und gib der Klasse dafür einige ReadOnly Properties.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Jopp, so ein Konstruktor erschlägt einen^^

    Ich würde das etwa so machen (sieht nach mehr aus als es ist):

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Dim ziel As New Ziel
    4. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    5. ziel.doMutation(New MutationCreep(...))
    6. End Sub
    7. End Class
    8. Public Class Ziel
    9. '' Falls notwendig kann eine Überladung auch eine 'allgemeine Mutation' (=> bekannter Typ: Typ der Oberklasse) entgegennehmen und an die entsprechende
    10. '' Überladung von doMutation() weiterreichen. Vorteil: du musst dich außerhalb nicht ums casten kümmern.
    11. ' Public Sub doMutation(ByVal mutation As MutationBase)
    12. ' Select Case mutation.MutationTyp
    13. ' Case eMutationTyp.Creep
    14. ' doMutation(DirectCast(mutation, MutationCreep)) 'leitet an die entsprechende überladung weiter
    15. '
    16. ' 'case ...
    17. '
    18. ' Case eMutationTyp.unbekannt
    19. ' '=> Exception
    20. ' End Select
    21. ' End Sub
    22. Public Sub doMutation(ByVal mutation As MutationCreep)
    23. 'Hier die konkrete Mutationsart abhandeln...
    24. End Sub
    25. Public Sub doMutation(ByVal mutation As MutationInsert)
    26. End Sub
    27. Public Sub doMutation(ByVal mutation As MutationSwap)
    28. End Sub
    29. End Class
    30. Public MustInherit Class MutationBase
    31. Private _mutationTyp As eMutationTyp = eMutationTyp.unbekannt
    32. Public Sub New(ByVal mutationTyp As eMutationTyp)
    33. _mutationTyp = mutationTyp
    34. End Sub
    35. Public ReadOnly Property MutationTyp As eMutationTyp
    36. Get
    37. Return _mutationTyp
    38. End Get
    39. End Property
    40. 'Mutationsrate würde ich hier deklarieren, da es laut deiner Aussage teil von ALLEN Unterklassen sein müsste
    41. End Class
    42. Public Enum eMutationTyp
    43. unbekannt
    44. Creep
    45. Insert
    46. Swap
    47. End Enum
    48. Public Class MutationCreep
    49. Inherits MutationBase
    50. Public Sub New()
    51. MyBase.New(eMutationTyp.Creep)
    52. End Sub
    53. 'Hier spezielle Mutationseigenschaften
    54. End Class
    55. Public Class MutationInsert
    56. Inherits MutationBase
    57. Public Sub New()
    58. MyBase.New(eMutationTyp.Insert)
    59. End Sub
    60. 'Hier spezielle Mutationseigenschaften
    61. End Class
    62. Public Class MutationSwap
    63. Inherits MutationBase
    64. Public Sub New()
    65. MyBase.New(eMutationTyp.Swap)
    66. End Sub
    67. 'Hier spezielle Mutationseigenschaften
    68. End Class



    Das sollte auf dein Problem passen, von

    VB.NET-Quellcode

    1. Dim P as new Population_Integer(...)
    2. P.SetParameters(Of Mutation_Creep_Properties)(2.0, 5.0)

    zu

    VB.NET-Quellcode

    1. Dim P as new Population_Integer(...)
    2. P.SetParameters(new Mutation_Creep_Properties(2.0, 5.0) )

    ist es ja kein weiter Weg^^

    lg

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

    Ich frage mich, warum ihr das alle so kompliziert machen wollt.
    Du kannst auch einfach ein ParamArray als Argument der Methode verwenden, dann kannst du beliebig viel übergeben. Je nachdem, welche Option gesetzt ist, wird das von der Methode dann unterschiedlich ausgewertet.
    @Artentus:
    Dann kannst Du das auch ordentlich machen und Instanzen von abgeleiteten Klassen übergeben, die alle Parameter beinhalten.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Artentus
    auch eine gute Idee xD
    Nachteil ist nur, dass IntelliSense einem nicht sagen kann was man als Parameter einzusetzen hat... man verkauft eine der größten Programmierhilfen für ein paar Zeilen eingesparten Code. (man spart ja nicht wirklich viel, immerhin muss man sich für jeden Enum-Fall erneut mit dem Parameter-Array herumschlagen etc). Bei kleineren Problemchen würde ich das vermutlich auch so machen, aber hier ist das zu komplex.
    Der Unterschied ist, dass der Aufruf dann wirklich so aussieht, wie in seinem ersten Post gewünscht und beliebige Typen übergeben werden können.
    Sollte man aber, wie Rod schon richtig gesagt hat, mit Klassen lösen.
    (Ich nehme einfach mal, dass du mich gemeint hast).
    Bisher habe ich bei ihm nur 2 Zahlen gesehen, mehr nicht.

    Und wie könnte ein ParamArray das Problem der unterschiedlichen Datentypen im Vergleich zu meinem Ansatz lösen?

    @Artentus
    Würde der Aufruf bei dir auch so aussehen, wie beim TE - dass man 2 Mal Argumentenpaare in () übergibt? SetParameters(bla)(bla1, bla2)?
    Also im Startpost schreibt er:

    VB.NET-Quellcode

    1. Private Sub Test()
    2. SetParameters(a)(test1, test2)
    3. SetParameters(b)(test1)
    4. End Sub


    Somit gibt er eine Unterschiedliche Anzahl an Parametern mit ( 'verschiedene Parameter' ), anderer Typ wäre auch noch denkbar.

    Darum würde ich das so wie Rod und Ich vorgeschlagen haben so lösen: [VB.NET] Parameter in Abhängigkeit von Enumeration
    (btw gibts dazu auch das passende Entwurfsmuster 'Besucher-Muster'. Meine Vorgeschlagene Variante ist etwas einfacher gehalten. Vorteil vom 'richtigen' Besucher-Muster wäre, dass man den Mutations-Code nichtmehr in der Ziel-Klasse hätte, sondern zentral in den Besucher-Klassen (=> der Klasse der Mutationsart). Soweit muss man aber denke ich nicht gehen)