91 votes

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, le nombre d’arguments est donc différent.

112voto

Darin Dimitrov Points 528142

Comme ceci:

Dictionary<int, Func<string, bool>>

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

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

Ou si la fonction n'est pas anonyme:

dico[5] = Foo;

où Foo est définie comme ceci:

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

Mise à JOUR:

Après avoir vu votre mise à jour, il semble que vous ne savez pas à l'avance à la signature de la fonction que vous souhaitez appeler. Dans .NET pour invoquer une fonction, vous devez passer tous les arguments et si vous ne savez pas ce que les arguments vont être la seule façon d'y parvenir est par le biais de 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 avez encore besoin de connaître le nombre et le type de paramètres qui doivent être transmis pour chaque fonction à l'index correspondant du dictionnaire ou vous obtiendrez une erreur d'exécution. Et si vos fonctions n'ont pas de valeurs de retour d'utilisation System.Action<> au lieu de System.Func<>.

8voto

Juliet Points 40758

Toutefois, la signature de la fonction n'est pas toujours le même, donc d'avoir différents nombre d'arguments.

Nous allons commencer avec un peu de fonctions définie comme ceci:

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

Vraiment vous avez 2 options viables à votre disposition:

1) Maintenir la sécurité du type par avoir des clients appelez votre fonction directement.

C'est probablement la meilleure solution, à moins d'avoir de très bonnes raisons de la rupture de ce modèle.

Quand vous parlez de vouloir intercepter les appels de fonction, il me semble que vous essayez de ré-inventer des fonctions virtuelles. Il y a une charge de bateau de façons d'obtenir ce genre de fonctionnalités prêtes à l'emploi, comme l'héritage d'une classe de base absolue de ses fonctions.

Il me semble que vous voulez une classe qui est plus d'un wrapper qu'un dérivé de l'instance d'une classe de base, donc faire quelque chose comme ceci:

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) OU d'une carte à l'entrée de vos fonctions à une interface commune.

Cela peut fonctionner si toutes les fonctions sont liées. Par exemple, si vous écrivez un jeu, et toutes les fonctions de faire quelque chose pour une certaine partie du joueur ou de l'inventaire du joueur. Vous auriez quelque chose comme ceci:

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

1voto

wvd_vegt Points 121

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 autorisera un nombre variable de paramètres.

1voto

Farax Points 402

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

0voto

smartcaveman Points 15610

Hey, 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);
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X