首页 > 解决方案 > C#:通过反射将通用多播委托分配给具有不同数量参数的操作

问题描述

因此,在我的班级中,一些代表都是 Action<...> 字段。例子:

public Action<int> onDiceRolled;
public Action<Turn, Round> onTurnEnded;

我想使用反射为他们每个人分配一个匿名函数。

    GetType().GetFields()
    .Where(field => field.FieldType.ToString().Contains("Action"))
    .ToList()
    .ForEach(field =>
    {
        Type type = field.FieldType; // e.g. Action<Turn, Round>
        if (!type.IsGenericType)
            return;

        Type[] para = type.GetGenericArguments(); // in example cases: {int} or {Turn, Round}
        MethodInfo debugMethod = (new Action(() => Console.WriteLine(field.Name + " was called."))).Method;
        field.SetValue(this, Delegate.CreateDelegate(type, debugMethod));
    });

当然这不起作用,因为创建的委托没有任何参数,而它需要的参数存储在 para. 不幸的是,我找不到通过类型数组创建委托的任何方法。

所以基本上我想做

onDiceRolled += (i) => Console.WriteLine("onDiceRolled was called.");

对于我班上的每个行动领域

标签: c#reflectiontypesdelegatesaction

解决方案


要设置委托,您可以使用表达式树来编译一个:

GetType().GetFields()
   .Where(field => field.FieldType.ToString().Contains("Action"))
   .ToList()
   .ForEach(field =>
   {
       Type type = field.FieldType; // e.g. Action<Turn, Round>
        if (!type.IsGenericType)
           return;

       Type[] para = type.GetGenericArguments(); // in example cases: {int} or {Turn, Round}
       Expression<Action> x = () => Console.WriteLine(field.Name + " was called.");
       var action = Expression.Lambda(x.Body, para.Select(p => Expression.Parameter(p))).Compile();
       field.SetValue(this, action);
   });

推荐阅读