2010-11-20 12 views
70

Wie erstelle ich ein Wörterbuch, in dem ich Funktionen speichern kann?C# Speichern von Funktionen in einem Wörterbuch

Danke.

Ich habe über 30 Funktionen, die vom Benutzer ausgeführt werden können. Ich möchte die Funktion auf diese Weise in der Lage sein, auszuführen:

private void functionName(arg1, arg2, arg3) 
    { 
     // code 
    } 

    dictionaryName.add("doSomething", functionName); 

    private void interceptCommand(string command) 
    { 
     foreach (var cmd in dictionaryName) 
     { 
      if (cmd.Key.Equals(command)) 
      { 
       cmd.Value.Invoke(); 
      } 
     } 
    } 

jedoch die Funktion Signatur nicht immer gleich ist, so unterschiedliche Menge an Argumenten haben.

+2

Dies ist ein großartiges Idiom - kann böse Schaltanweisungen ersetzen. –

+0

Ihre Beispielfunktion hat Parameter. Wenn Sie die gespeicherte Funktion aufrufen, rufen Sie sie jedoch ohne Argumente auf. Sind die Argumente beim Speichern der Funktion behoben? –

+0

Das war nur ein schlecht geschriebenes Beispiel für mich. Ich weiß nicht, ein Wörterbuch zu erstellen, das es tun würde, weil die Funktionssignatur immer anders ist. – chi

Antwort

81

So:

Dictionary<int, Func<string, bool>> 

Auf diese Weise können Sie Funktionen speichern, die einen String-Parameter übernehmen und boolean zurück.

dico[5] = foo => foo == "Bar"; 

Oder, wenn die Funktion nicht anonym:

dico[5] = Foo; 

wo Foo wie folgt definiert ist:

public bool Foo(string bar) 
{ 
    ... 
} 

UPDATE: es

Nachdem ich das Update scheint, dass Sie nicht im Voraus wissen die Signatur der Funktion, die Sie aufrufen möchten. Um in .NET eine Funktion aufzurufen, müssen Sie alle Argumente übergeben, und wenn Sie nicht wissen, was die Argumente sein werden, können Sie dies nur durch Reflexion erreichen.

Und hier ist eine andere Alternative:

class Program 
{ 
    static void Main() 
    { 
     // store 
     var dico = new Dictionary<int, Delegate>(); 
     dico[1] = new Func<int, int, int>(Func1); 
     dico[2] = new Func<int, int, int, int>(Func2); 

     // and later invoke 
     var res = dico[1].DynamicInvoke(1, 2); 
     Console.WriteLine(res); 
     var res2 = dico[2].DynamicInvoke(1, 2, 3); 
     Console.WriteLine(res2); 
    } 

    public static int Func1(int arg1, int arg2) 
    { 
     return arg1 + arg2; 
    } 

    public static int Func2(int arg1, int arg2, int arg3) 
    { 
     return arg1 + arg2 + arg3; 
    } 
} 

Mit diesem Ansatz müssen Sie noch die Anzahl und Art der Parameter kennen, die jeder Funktion in dem entsprechenden Index des Wörterbuchs übergeben werden müssen, oder Sie werden Laufzeit erhalten Error. Und wenn Ihre Funktionen keine Rückgabewerte haben, verwenden Sie System.Action<> anstelle von System.Func<>.

+0

Ich verstehe. Ich denke, ich werde einige Zeit damit verbringen müssen, über Reflexion zu lesen, dann schätze ich die Hilfe. – chi

+0

@chi, siehe mein letztes Update. Ich habe ein Beispiel mit 'Dictionary ' hinzugefügt. –

+0

Auch mit dem 'Delegate()' Modell können Sie die 'dico' Werte nicht zusammensetzen:' dico [1] + = neuer Func <...> (Func3) 'also führt nun dico [1] Func1 und dann Func3 aus? – IAbstract

9

jedoch ist die Funktion Signatur nicht immer gleich ist, damit unterschiedliche Menge von Argumenten aufweist.

Lassen Sie uns mit ein paar Funktionen wie folgt definiert starten:

private object Function1() { return null; } 
private object Function2(object arg1) { return null; } 
private object Function3(object arg1, object arg3) { return null; } 

Sie wirklich zwei praktikable Möglichkeiten zur Verfügung haben:

1) nach Typ-Sicherheit pflegen Kunden rufen Sie Ihre Funktion direkt.

Dies ist wahrscheinlich die beste Lösung, es sei denn, Sie haben sehr gute Gründe für das Brechen von diesem Modell.

Wenn Sie über das Abfangen von Funktionsaufrufen sprechen, klingt es für mich so, als wollten Sie virtuelle Funktionen neu erfinden. Es gibt eine Reihe von Möglichkeiten, um diese Art von Funktionalität aus der Box zu bekommen, wie beispielsweise das Erben von einer Basisklasse und das Überschreiben ihrer Funktionen.

Es klingt für mich wie Sie eine Klasse wollen, die als eine abgeleitete Instanz einer Basisklasse eher ein Wrapper ist, so etwas tun, wie folgt aus:

public interface IMyObject 
{ 
    object Function1(); 
    object Function2(object arg1); 
    object Function3(object arg1, object arg2); 
} 

class MyObject : IMyObject 
{ 
    public object Function1() { return null; } 
    public object Function2(object arg1) { return null; } 
    public object Function3(object arg1, object arg2) { return null; } 
} 

class MyObjectInterceptor : IMyObject 
{ 
    readonly IMyObject MyObject; 

    public MyObjectInterceptor() 
     : this(new MyObject()) 
    { 
    } 

    public MyObjectInterceptor(IMyObject myObject) 
    { 
     MyObject = myObject; 
    } 

    public object Function1() 
    { 
     Console.WriteLine("Intercepted Function1"); 
     return MyObject.Function1(); 
    } 
    public object Function2(object arg1) 
    { 
     Console.WriteLine("Intercepted Function2"); 
     return MyObject.Function2(arg1); 
    } 

    public object Function3(object arg1, object arg2) 
    { 
     Console.WriteLine("Intercepted Function3"); 
     return MyObject.Function3(arg1, arg2); 
    } 
} 

2) oder eine Karte die Eingabe von Ihre Funktionen zu einer gemeinsamen Schnittstelle.

Dies könnte funktionieren, wenn alle Ihre Funktionen verwandt sind. Zum Beispiel, wenn Sie ein Spiel schreiben und alle Funktionen etwas mit dem Inventar des Spielers oder Spielers tun. Sie würden am Ende mit so etwas enden:

class Interceptor 
{ 
    private object function1() { return null; } 
    private object function2(object arg1) { return null; } 
    private object function3(object arg1, object arg3) { return null; } 

    Dictionary<string, Func<State, object>> functions; 

    public Interceptor() 
    { 
     functions = new Dictionary<string, Func<State, object>>(); 
     functions.Add("function1", state => function1()); 
     functions.Add("function2", state => function2(state.arg1, state.arg2)); 
     functions.Add("function3", state => function3(state.arg1, state.are2, state.arg3)); 
    } 

    public object Invoke(string key, object state) 
    { 
     Func<object, object> func = functions[key]; 
     return func(state); 
    } 
} 
+2

Was ist "Staat"? – MrHIDEn

+0

Staat ist Klasse? – Sandip

+0

Meine Annahme wäre ein "Objekt" wie das, das an einen neuen Thread übergeben würde. –

0

Hey, ich hoffe, das hilft. Aus welcher Sprache kommst du?

internal class ForExample 
{ 
    void DoItLikeThis() 
    { 
     var provider = new StringMethodProvider(); 
     provider.Register("doSomethingAndGetGuid", args => DoSomeActionWithStringToGetGuid((string)args[0])); 
     provider.Register("thenUseItForSomething", args => DoSomeActionWithAGuid((Guid)args[0],(bool)args[1])); 


     Guid guid = provider.Intercept<Guid>("doSomethingAndGetGuid", "I don't matter except if I am null"); 
     bool isEmpty = guid == default(Guid); 
     provider.Intercept("thenUseItForSomething", guid, isEmpty); 
    } 

    private void DoSomeActionWithAGuid(Guid id, bool isEmpty) 
    { 
     // code 
    } 

    private Guid DoSomeActionWithStringToGetGuid(string arg1) 
    { 
     if(arg1 == null) 
     { 
      return default(Guid); 
     } 
     return Guid.NewGuid(); 
    } 

} 
public class StringMethodProvider 
{ 
    private readonly Dictionary<string, Func<object[], object>> _dictionary = new Dictionary<string, Func<object[], object>>(); 
    public void Register<T>(string command, Func<object[],T> function) 
    { 
     _dictionary.Add(command, args => function(args)); 
    } 
    public void Register(string command, Action<object[]> function) 
    { 
     _dictionary.Add(command, args => 
            { 
             function.Invoke(args); 
             return null; 
            }); 
    } 
    public T Intercept<T>(string command, params object[] args) 
    { 
     return (T)_dictionary[command].Invoke(args); 
    } 
    public void Intercept(string command, params object[] args) 
    { 
     _dictionary[command].Invoke(args); 
    } 
} 
1

Warum params object[] list nicht für Methodenparameter und Ihre Methoden einige Prüfungen durchführen innerhalb einer (oder Aufruf Logik), Es wird für eine variable Anzahl von Parametern ermöglichen.

0

Im folgenden Szenario können Sie ein Elementwörterbuch als Eingabeparameter verwenden und dasselbe wie die Ausgabeparameter abrufen.

zuerst die folgende Zeile an der Spitze hinzu:

using TFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Collections.Generic.IDictionary<string, object>>; 

Dann in Ihrer Klasse definiert das Wörterbuch wie folgt:

 private Dictionary<String, TFunc> actions = new Dictionary<String, TFunc>(){ 

         {"getmultipledata", (input) => 
          { 
           //DO WORKING HERE 
           return null; 
          } 
         }, 
         {"runproc", (input) => 
          { 
           //DO WORKING HERE 
           return null; 
          } 
         } 
}; 

Dies würde ermöglicht es Ihnen, diese anonymen Funktionen mit einer Syntax laufen Ähnliches:

var output = actions["runproc"](inputparam); 
Verwandte Themen