如何让用户可以将任何类型的方法添加到我的字典<string,delegate>?</string,delegate>

时间:2013-08-29 16:32:42

标签: c# delegates

我需要添加任何返回double的方法并将任意数量的双参数添加到Dictionary中。请帮帮我。

class Program
{
Dictionary<string, Delegate> _functions;
static double MyFunc (double x, double y, double z, double q, double r, double t)
    {
        return 100;
    }
// and the user can create his functions with any amount of parameters
static void AddFunction (Delegate d)
    {            
        _functions.Add (d.Method.Name, d);
    } 
static void Main (string [] args)
    {
        _functions = new Dictionary<string, Delegate> ();
        Program.AddFunction(MyFunc);
    }
} 

5 个答案:

答案 0 :(得分:1)

好吧,我不确定你打算怎么打算这个。由于您有变量数量的输入,您可以将它们视为数组输入。

delegate double MyDictionaryDelegate(params double[] input);

static Dictionary<string, MyDictionaryDelegate> _functions;

static void AddFunction (MyDictionaryDelegate d)
{            
   _functions.Add(d.Method.Name, d);
} 

但是,这实际上将您的被调用函数转换为处理集合(具有这意味着的任何好处/限制):

public static double MyFunc (params double[] input)
{
   return input.Sum();
}

所以你的用法可能是:

_functions = new Dictionary<string, MyDictionaryDelegate> ();
AddFunction(MyFunc);
Console.WriteLine(_functions["MyFunc"](1, 2.5, 0));//3.5

但我怀疑你宁愿保留参数参数的原始列表而不是列表,如下所示:

public static double AnotherFunc(double x, double y, double z)
{
    return x + y + z;
}

可以只有一个包装函数:

public static double AnotherFunc(params double[] input)
{
    //preferably with some check that the proper number of 
    //input parameters are included
    return AnotherFuncImpl(input[0], input[1], input[2]);
}

但这对我来说似乎总体上是危险的;我不确定我会推荐它。

编辑:这是避免param double[] input数组并且始终具有固定参数参数的另一个选项。尽可能使用Delegate,但您必须使用DynamicInvoke。此外,您要为您希望合理拥有的每个参数声明多个AddFunction重载:

static Dictionary<string, Delegate> _functions;

private static void AddFunction (string functionName, Delegate d)
{            
   _functions.Add(functionName, d);
} 

private static void AddFunction(Func<double> d)
{            
   _functions.Add(d.Method.Name, d);
} 

private static void AddFunction(Func<double, double> d)
{            
   _functions.Add(d.Method.Name, d);
} 

private static void AddFunction(Func<double, double, double> d)
{            
   _functions.Add(d.Method.Name, d);
} 

private static void AddFunction(Func<double, double, double, double> d)
{            
   _functions.Add(d.Method.Name, d);
} 

//additional overloads up to N parameters

然后用法可能是:

public static double MyFunc(double x, double y, double z)
{
    return x + y + z;
}

_functions = new Dictionary<string, Delegate> ();
AddFunction(MyFunc);
Console.WriteLine(_functions["MyFunc"].DynamicInvoke(1, 2.5, 0));//3.5

但是如果调用者没有使用所需参数的确切数字正确调用DynamicInvoke,则可能会失败。(不多也不少)。

我仍然觉得整体而言,无论你做什么,都会受益于不同的设计。

答案 1 :(得分:0)

定义一个新的类对象,它具有您需要的委托和参数列表,然后dictionary<string, clsObject>将是您定义字典的方式。

答案 2 :(得分:0)

将该方法添加到集合中时,将该方法强制转换为Func<T1, T2, .., TResult>

Program.AddFunction(
    (Func<double, double, double, double, double, double, double>)MyFunc);

答案 3 :(得分:0)

你的意思是defining a delegate with the params modifier on its arguments吗?答案显然是否定的,因为编译器会在方法调用中将其他参数转换为数组,但对于委托则不会。请参阅链接以获取一些解决方案。

答案 4 :(得分:0)

你需要将你的委托声明为返回一个double,然后取一个双打的参数,这是一个完整的例子。

public class Widget
{
    // declares a delegate called AddDelegate that takes a param of doubles
    public delegate double AddDelegate(params double[] dbls);
    Dictionary<string, AddDelegate> functions;

    public Widget()
    {
        functions = new Dictionary<string, AddDelegate>();
    }

    public void Add(AddDelegate d)
    {
        functions.Add(d.Method.Name, d);
    }

    public void Run()
    {
        foreach (var kvp in functions)
        {
            // write out the name and result of each function added to our list
            Console.Write(kvp.Key);
            Console.Write(": ");
            Console.Write(kvp.Value(10.0, 10.0, 10.0, 10.0));
        }
    }
}

class Program
{
    static double CalcDouble(params double[] dbls)
    {
        double total = 0.0;
        foreach (double d in dbls)
        {
            total += d;
        }
        return total;
    }


    static void Main(string[] args)
    {
        var w = new Widget();
        w.Add(new Widget.AddDelegate(CalcDouble));
        w.Run();
    }
}