Zufällige methode verwenden

  • C#
  • .NET (FX) 4.0

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Rikudo.

    Zufällige methode verwenden

    Hallo Community,

    Da ich nach einiger Recherche keine hilfreichen Informationen finden konnte frage ich hier im Forum.
    Und zwar: Ich möchte in einer bestimmten Funktion meine Daten weiterverarbeiten.
    Dies kann allerdings auf verschiedene Wege passieren, da es mehrere Methoden in mehreren Klassen gibt die diese
    Daten unterschiedlich verarbeiten können.
    Sagen wir ich habe Class1, Class2, Class3 ... Class10 und in jeder Class gibt es die Methoden mit den gleichen Parametern
    method1, method2, method3 ... method10.
    In meiner Funktion soll jetzt zufällig eine Class und die jeweilige Methode ausgewählt werden, welche dann die Daten weiterverarbeitet.
    Ich möchte das ganze nicht in ein riesiges Switch statement packen, ich bin mir sicher da gibt es elegantere Lösungen, List<Method> oder sowas? Aus der man dann zufällig auswählen kann.

    Lg
    Rikudo
    C# Developer
    Learning C++

    EaranMaleasi schrieb:

    Oder aber, sofern die Methoden die gleiche Signatur haben, könntest du ja auch ein Interface Implementieren und dann alles in eine List<IDeinInterface> packen.

    Das klingt auf jeden Fall sehr OO.
    Kannst du mal in Pseudocode aufzeigen wie ein solches Construct aussehen würde?
    C# Developer
    Learning C++
    Das Problem ist halt, dass man von Hand die ganzen Instanzen erstellen muss:

    C#-Quellcode

    1. interface IStuffDoer {
    2. void DoIt();
    3. }
    4. class StuffDoer1 : IStuffDoer { ... }
    5. class StuffDoer2 : IStuffDoer { ... }
    6. //...
    7. var StuffDoers = new List<IStuffDoer>();
    8. StuffDoers.Add(new StuffDoer1());
    9. StuffDoers.Add(new StuffDoer2());
    10. //...

    Aber man kann die Instanzen auch per Reflection erstellen. Da alle Klassen das IStuffDoer-Interface implementieren, ist es recht einfach, da dran zu kommen:

    C#-Quellcode

    1. var StuffDoers = (from Candidate in typeof(IStuffDoer).Assembly.GetTypes() // Finde alle Typen, ...
    2. let Interfaces = Candidate.GetInterfaces()
    3. where Interfaces.Contains(typeof(IStuffDoer)) // die das IStuffDoer-Interface implementieren ...
    4. let Instance = (IStuffDoer)Activator.CreateInstance(Candidate) // und erstelle eine Instanz davon.
    5. select Instance).ToList(); // ToList, damit das alles sofort ausgeführt wird (statt "Lazy").

    Dann kannst Du aus der Liste einfach eine Instanz rausholen und daran Deine Methoden aufrufen.

    Ein Hinweis noch: Activator.CreateInstance verwendet den Konstruktor ohne Parameter. Wenn Deine Klassen keinen solchen Konstruktor haben, dann funktioniert das so nicht.
    Ruf stattdessen an Candidate die GetConstructor-Funktion mit den BindingFlags Public und Instance und den passenden Parametertypen auf. Als Binder und Modifiers kannst Du null angeben.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    ErfinderDesRades schrieb:

    Man könnte auch eine List<delegate> nehmen - da spart man sich den Interface-Heckmeck.
    Ich sags gleich: Ich liefere Code, wenn Rikudo Code seiner Klassen liefert mit den Methoden drin, die je was verschiedenes machen.

    Du weißt dass das sehr provokant klingt, oder?

    Es geht um so genannte Constantmutation in meiner Software (Obfsuaktor-related).
    Dabei wird eine constante in eine rechnung zerlegt.

    Dafür habe ich mir eine Klasse Expression erstellt:

    Quellcode

    1. public abstract class Expression
    2. {
    3. public abstract IList<Instruction> GenerateIL();
    4. }


    Die Klasse BinaryOperatorExpression erbt davon :

    Quellcode

    1. public class BinaryOperatorExpression : Expression
    2. {
    3. public BinaryOperatorExpression(Expression left, OpCode @operator, Expression right)
    4. {
    5. Left = left;
    6. Operator = @operator;
    7. Right = right;
    8. }
    9. public Expression Left
    10. {
    11. get;
    12. set;
    13. }
    14. public OpCode Operator
    15. {
    16. get;
    17. set;
    18. }
    19. public Expression Right
    20. {
    21. get;
    22. set;
    23. }
    24. public override IList<Instruction> GenerateIL()
    25. {
    26. var result = new List<Instruction>();
    27. result.AddRange(Left.GenerateIL()); // Push left expression (first stack value)
    28. result.AddRange(Right.GenerateIL()); // Push right expression (second stack value)
    29. result.Add(Instruction.Create(Operator)); // Push operator (OpCode such as Add)
    30. return result;
    31. }
    32. }


    Diese Klasse wird benötigt um den entsprechenden IL-Code zu generieren.
    Hier mal ein Beispiel für die Klassen die die Methoden enthalten die später zufällig gewählt werden sollen:

    Quellcode

    1. class AddMutation
    2. {
    3. private static Random rnd = new Random();
    4. private static BinaryOperatorExpression Generate(int value)
    5. {
    6. int rndValue = rnd.Next(0, 100000);
    7. Int32Expression expression = new Int32Expression(value);
    8. return new BinaryOperatorExpression(
    9. new Int32Expression(expression.Value - rndValue),
    10. OpCodes.Add,
    11. new Int32Expression(value));
    12. }
    13. }



    Davon gibt es jetzt viele Klassen mit Methoden die genau gleich aufgebaut sind, allerdings mit Subtraktion, Multiplikation usw.
    Ziel ist jetzt, sobald die Input-Daten geliefert werden, soll zufällig eine dieser Methoden darauf angewandt werden.
    Zuerst wollte ich sowas machen:

    Quellcode

    1. private static void Mutate(MethodDef method, int number, ref int i)
    2. {
    3. //switch (rnd.Next(0, 5))
    4. //{
    5. // case 0: { Class1.MutateAdd(..) } // Add
    6. // case 1: { Class2.MutateSub(..) } // Sub
    7. // case 2: { Class3.MutateMul(..) } // Mul
    8. // case 3: { Class4.MutateMod(..) } // Mod
    9. // ...
    10. //}
    11. }


    Allerdings scheint mir das nicht sonderlich objektorientiert und auch sehr ineffizient wenn man nicht nur 5 sondern mehrere Klassen hat.
    Daher interessiert mich die Idee von Niko Ortner mit den Interfaces bzw die delegate methode von ErfinderDesRades sehr.

    Es geht also quasi darum random entweder die Add, Sub, Mul funktion usw auf den input anzuwenden. Und das ganze möglichst ObjectOrientiert aufzubauen.
    C# Developer
    Learning C++
    Hmm - mit deine Klassen habich nicht viel anfangen können - fehlt ja mehr als die Hälfte, dass ichs ühaupt zu kompilieren kriege.

    Sorry für die provokante Ansage - im annern Forum wars halt mal wieder so, dass ich erst eine Lösung code, dann gefragt werde, wie man die nun aufruft, und dann, wie man die nun in sein Programm einbauen kann.

    Also ganze Arbeit für Katz.

    Also hier alle möglichen Übungen mit Delegaten

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Diagnostics;
    4. using System.Linq;
    5. using System.Runtime.CompilerServices;
    6. public class DebuggerOutput {
    7. protected virtual void Msg(object o, [CallerMemberName()]string methodName = "") {
    8. MsgStatic(this.GetType().Name, o, methodName);
    9. }
    10. public static void MsgStatic(string sender, object o, [CallerMemberName()]string methodName = "") {
    11. Debug.WriteLine("{0}.{1}: {2}", sender, methodName, o);
    12. }
    13. }
    14. public class Summerer : DebuggerOutput {
    15. public int Add(int x, int y) {
    16. var result = x + y;
    17. Msg(result);
    18. return result;
    19. }
    20. }
    21. public class Subtracter : DebuggerOutput {
    22. public int Subtract(int x, int y) {
    23. var result = x - y;
    24. Msg(result);
    25. return result;
    26. }
    27. }
    28. public class Multiplyer : DebuggerOutput {
    29. public int Multiply(int x, int y) {
    30. var result = x * y;
    31. Msg(result);
    32. return result;
    33. }
    34. }
    35. public class Divider : DebuggerOutput {
    36. public int Divide(int x, int y) {
    37. var result = x / y;
    38. Msg(result);
    39. return result;
    40. }
    41. }
    42. public static class AllesKönner {
    43. public static void TuAlles() {
    44. var functions = new List<Func<int, int, int>>();
    45. functions.Add(AllesKönner.Add);
    46. functions.Add(AllesKönner.Subtract);
    47. functions.Add(AllesKönner.Multiply);
    48. functions.Add(AllesKönner.Divide);
    49. var f = new Summerer();
    50. functions.Add(f.Add);
    51. functions.Add(new Subtracter().Subtract);
    52. functions.Add(new Multiplyer().Multiply);
    53. functions.Add(new Divider().Divide);
    54. var rnd = new Random(99);
    55. while (true) {
    56. var x = rnd.Next(10, 101);
    57. var y = rnd.Next(10, 101);
    58. var i = rnd.Next(0, functions.Count);
    59. Debug.WriteLine("x: {0}, y: {1}", x, y);
    60. functions[i].Invoke(x, y);
    61. System.Threading.Thread.Sleep(300);
    62. }
    63. }
    64. public static int Add(int x, int y) {
    65. var result = x + y;
    66. DebuggerOutput.MsgStatic("AllesKönner", result);
    67. return result;
    68. }
    69. public static int Subtract(int x, int y) {
    70. var result = x - y;
    71. DebuggerOutput.MsgStatic("AllesKönner", result);
    72. return result;
    73. }
    74. public static int Multiply(int x, int y) {
    75. var result = x * y;
    76. DebuggerOutput.MsgStatic("AllesKönner", result);
    77. return result;
    78. }
    79. public static int Divide(int x, int y) {
    80. var result = x / y;
    81. DebuggerOutput.MsgStatic("AllesKönner", result);
    82. return result;
    83. }
    84. }
    Ist Konsole-Anwendung, und AllesKönner.TuAlles() tut alles:
    Es werden statische Delegaten und Delegaten von Objekten in die Liste geschmissen, die Objekte erben da bischen herum, oder auch nicht (AllesKönner hats nicht nötig), und jo.

    Die Ausgabe ist auch wirklich recht chaotisch

    Quellcode

    1. x: 50, y: 88
    2. Divider.Divide: 0
    3. x: 72, y: 92
    4. AllesKönner.Add: 164
    5. x: 33, y: 19
    6. AllesKönner.Subtract: 14
    7. x: 80, y: 30
    8. Multiplyer.Multiply: 2400
    9. x: 72, y: 98
    10. AllesKönner.Multiply: 7056
    11. x: 88, y: 53
    12. AllesKönner.Divide: 1
    13. x: 42, y: 68
    14. Divider.Divide: 0
    15. x: 22, y: 75
    16. Summerer.Add: 97
    17. x: 46, y: 28
    18. AllesKönner.Add: 74
    19. x: 12, y: 91
    20. Multiplyer.Multiply: 1092
    21. x: 76, y: 58
    22. AllesKönner.Add: 134
    23. x: 52, y: 29
    24. AllesKönner.Add: 81
    25. x: 13, y: 87
    26. AllesKönner.Multiply: 1131
    27. x: 25, y: 56
    28. AllesKönner.Subtract: -31

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