简体   繁体   English

C# 将函数存储在字典中

[英]C# Store functions in a Dictionary

How do I create a Dictionary where I can store functions?如何创建可以存储函数的字典?

Thanks.谢谢。

I have about 30+ functions which can be executed from the user.我有大约 30 多个可以由用户执行的功能。 I want to be able to execute the function this way:我希望能够以这种方式执行该功能:

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

However, the function signature is not always the same, thus having different amount of arguments.但是,函数签名并不总是相同的,因此具有不同数量的参数。

Like this:像这样:

Dictionary<int, Func<string, bool>>

This allows you to store functions that take a string parameter and return boolean.这允许您存储采用字符串参数并返回布尔值的函数。

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

Or if the function is not anonymous:或者如果函数不是匿名的:

dico[5] = Foo;

where Foo is defined like this:其中 Foo 定义如下:

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

UPDATE:更新:

After seeing your update it seems that you don't know in advance the signature of the function you would like to invoke.看到您的更新后,您似乎事先不知道要调用的函数的签名。 In .NET in order to invoke a function you need to pass all the arguments and if you don't know what the arguments are going to be the only way to achieve this is through reflection.在 .NET 中,为了调用一个函数,您需要传递所有参数,如果您不知道参数是什么,那么实现此目的的唯一方法是通过反射。

And here's another 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;
    }
}

With this approach you still need to know the number and type of parameters that need to be passed to each function at the corresponding index of the dictionary or you will get runtime error.使用这种方法,您仍然需要知道需要在字典的相应索引处传递给每个函数的参数的数量和类型,否则会出现运行时错误。 And if your functions doesn't have return values use System.Action<> instead of System.Func<> .如果您的函数没有返回值,请使用System.Action<>而不是System.Func<>

However, the function signature is not always the same, thus having different amount of arguments.但是,函数签名并不总是相同的,因此具有不同数量的参数。

Let's start with a few functions defined like this:让我们从几个这样定义的函数开始:

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

You really have 2 viable options at your disposal:您确实有两个可行的选择:

1) Maintain type-safety by having clients call your function directly. 1)通过让客户直接调用您的函数来维护类型安全。

This is probably the best solution, unless you have very good reasons for breaking from this model.这可能是最好的解决方案,除非你有很好的理由打破这种模式。

When you talk about wanting to intercept function calls, it sounds to me like you're trying to re-invent virtual functions.当你谈到想要拦截函数调用时,我觉得你是在尝试重新发明虚函数。 There's a boat load of ways to get this sort of functionality out of the box, such as inheriting from a base class an overriding its functions.有很多方法可以开箱即用地获得这种功能,例如从基类继承并覆盖其功能。

It sounds to me like you want a class that's more of a wrapper than a derived instance of a base class, so do something like this:在我看来,您想要一个更像是包装器而不是基类的派生实例的类,所以请执行以下操作:

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 map the input of your functions to a common interface. 2)或将您的函数的输入映射到一个通用接口。

This might work if all of your functions are related.如果您的所有功能都相关,这可能会起作用。 For example, if you're writing a game, and all the functions do something to some part of the player or player's inventory.例如,如果您正在编写游戏,并且所有函数都对玩家或玩家库存的某些部分执行某些操作。 You'd end up with something like this:你最终会得到这样的东西:

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

Define the dictionary and add the function reference as the value, using System.Action as the type:定义字典并添加函数引用作为值,使用System.Action作为类型:

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

Then invoke it with:然后调用它:

Actions.myActions["myKey"]();

Hey, I hope this helps.嘿,我希望这会有所帮助。 What language are you coming from?你来自什么语言?

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

为什么不对方法参数使用params object[] list并在您的方法(或调用逻辑)内部进行一些验证,它将允许可变数量的参数。

The following scenario would allow you to use a dictionary of elements to send in as input parameters and get the same as the output parameters.以下场景将允许您使用元素字典作为输入参数发送并获得与输出参数相同的内容。

First add the following line at the top:首先在顶部添加以下行:

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

Then inside your class, define the dictionary as follows:然后在你的类中,定义字典如下:

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

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

This would allow you to run these anonymous functions with a syntax similar to this:这将允许您使用类似于以下的语法运行这些匿名函数:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM