web-dev-qa-db-fra.com

Fonctions de magasin C # dans un dictionnaire

Comment créer un dictionnaire dans lequel je peux stocker des fonctions?

Merci.

J'ai environ 30 fonctions pouvant être exécutées par l'utilisateur. Je veux pouvoir exécuter la fonction de cette façon:

   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();
            }
        }
    }

Cependant, la signature de la fonction n’est pas toujours la même, ce qui donne un nombre différent d’arguments. 

79
chi

Comme ça:

Dictionary<int, Func<string, bool>>

Cela vous permet de stocker des fonctions qui prennent un paramètre de chaîne et renvoient un booléen.

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

Ou si la fonction n'est pas anonyme:

dico[5] = Foo;

où Foo est défini comme ceci:

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

METTRE À JOUR: 

Après avoir vu votre mise à jour, il semble que vous ne connaissiez pas à l'avance la signature de la fonction que vous souhaitez invoquer. Dans .NET, pour appeler une fonction, vous devez transmettre tous les arguments. Si vous ne savez pas quels arguments seront le seul moyen d'y parvenir, vous devez utiliser la réflexion.

Et voici une autre 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;
    }
}

Avec cette approche, vous devez toujours connaître le nombre et le type de paramètres à transmettre à chaque fonction dans l'index correspondant du dictionnaire, sinon vous obtiendrez une erreur d'exécution. Et si vos fonctions n'ont pas de valeur de retour, utilisez System.Action<> au lieu de System.Func<>.

97
Darin Dimitrov

Cependant, la signature de fonction n'est pas toujours le même, donc différent quantité d'arguments.

Commençons par quelques fonctions définies comme ceci:

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

Vous avez vraiment 2 options viables à votre disposition:

1) Veillez à la sécurité du type en demandant aux clients d'appeler directement votre fonction.

C’est probablement la meilleure solution, à moins que vous n’ayez très de bonnes raisons de rompre avec ce modèle.

Lorsque vous parlez de vouloir intercepter des appels de fonction, il me semble que vous essayez de réinventer les fonctions virtuelles. Il existe de nombreuses méthodes pour obtenir ce type de fonctionnalité, telles que l'héritage d'une classe de base en remplaçant ses fonctions.

Il me semble que vous voulez une classe qui ressemble plus à un wrapper qu’une instance dérivée d’une classe de base, procédez comme suit:

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) OR mappe l'entrée de vos fonctions sur une interface commune.

Cela pourrait fonctionner si toutes vos fonctions sont liées. Par exemple, si vous écrivez un jeu et que toutes les fonctions font quelque chose pour une partie de l'inventaire du joueur ou du joueur. Vous vous retrouveriez avec quelque chose comme ça:

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);
    }
}
9
Juliet

Pourquoi ne pas utiliser params object[] list pour les paramètres de méthode et effectuer une validation dans vos méthodes (ou dans la logique d’appel), cela permettra un nombre variable de paramètres.

1
wvd_vegt

Le scénario suivant vous permettrait d'utiliser un dictionnaire d'éléments à envoyer en tant que paramètres d'entrée et d'obtenir le même résultat que les paramètres de sortie.

Commencez par ajouter la ligne suivante en haut:

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

Ensuite, dans votre classe, définissez le dictionnaire comme suit:

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

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

Cela vous permettrait d’exécuter ces fonctions anonymes avec une syntaxe semblable à celle-ci:

var output = actions["runproc"](inputparam);
0
Farax

Hé, j'espère que ça aide. De quelle langue venez-vous?

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);
    }
}
0
smartcaveman

Définissez le dictionnaire et ajoutez la référence de la fonction comme valeur, en utilisant System.Action comme type:

using System.Collections;
using System.Collections.Generic;

public class Actions {

    public Dictionary<string, System.Action> myActions = new Dictionary<string, System.Action>();

    public Actions() {
        myActions ["myKey"] = TheFunction;
    }

    public void TheFunction() {
        // your logic here
    }
}

Puis invoquez-le avec:

Actions.myActions["myKey"]();
0
modle13