如何在运行时定义委托类型(即动态委托类型)

时间:2010-10-27 09:25:30

标签: c# delegates

为了动态创建代理,技术各不相同,从Delegate.CreateDelegate到Expresion Lambda,DynamicMethod等等。所有这些技术都要求您知道委托的类型

我正在尝试将已关闭的委托转换为打开委托一般,为了实现这一点,我似乎需要在实际创建结果委托之前动态创建开放委托的类型。考虑:

pubic class WeakEvent<TDelegate> where TDelegate : class
{
     public WeakEvent(Delegate aDelegate)
     {
         var dgt = aDelegate as TDelegate;

         if(dgt == null)
             throw new ArgumentException("aDelegate");

         MethodInfo method = dgt.Method;
         var parameters = Enumerable
                         .Repeat(dgt.Target.GetType(),1)
                         .Concat(method.GetParameters().Select(p => p.ParameterType));

         Type openDelegateType = // ???  original delegate, with new 1st arg for @this

         var dm = new DynamicMethod("InnerCode", method.ReturnType, parameters);

         ... your favourite IL code emmisions go here

         var openDelegate = dm.CreateDelegate(openDelegateType);
     }
}

上述代码的purpsoe是创建一个与原始委托相同的新委托,但是对于 this 有一个新的第一个参数...即先前关闭的委托的开放版本。

是否有一种简单的方法来克隆&amp;修改现有的委托类型,或者是构建通用Func&lt;&gt;的最近解决方案和行动&lt;&gt;类型?

3 个答案:

答案 0 :(得分:1)

具有不同签名的新委托是一种新类型。 C#是类型安全的,不可能这样做 - 除了搅拌一些代码并在运行时编译,除了内存泄漏不是一种优雅的方法。

但你可以做的是从已经制作的Action&lt;&gt;列表中选择合适的委托。或者Func&lt;&gt;基于代表的类型。或者根据您的预期类型创建自己的lits,并在运行时选择它。

答案 1 :(得分:1)

经过一番经验,我发现以下代码是实现我希望的最佳方式:

    private Type CreateOpenDelegate()
    {
        var parms = _method.GetParameters();
        bool hasReturn = _method.ReturnType != typeof (void);
        Type generic = GetGenericTypeForOpenDelegate(parms, hasReturn);

        var argTypes = new List<Type>(parms.Length + 2) {_method.DeclaringType};

        foreach (var arg in parms)
        {
            if(arg.IsOut || arg.IsRetval)
                throw new NotImplementedException();

            argTypes.Add(arg.ParameterType);
        }

        if(hasReturn)
            argTypes.Add(_method.ReturnType);

        var result = generic.MakeGenericType(argTypes.ToArray());

        return result;
    }

    private static Type GetGenericTypeForOpenDelegate(ParameterInfo[] parms, bool hasReturn)
    {
        if (hasReturn)
        {
            switch (parms.Length)
            {
                case 0:
                    return typeof (Func<,>);
                    break;
                case 1:
                    return typeof (Func<,,>);
                    break;
                case 2:
                    return typeof (Func<,,,>);
                    break;
                case 3:
                    return typeof (Func<,,,,>);
                    break;
            }
        }
        else
        {
            switch (parms.Length)
            {
                case 0:
                    return typeof (Action<>);
                    break;
                case 1:
                    return typeof (Action<,>);
                    break;
                case 2:
                    return typeof (Action<,,>);
                    break;
                case 3:
                    return typeof (Action<,,,>);
                    break;
            }
        }
        throw new NotImplementedException();
    }

这是一种耻辱,因为它意味着(据我所知),你无法使用 ref out 参数动态[重新]创建委托,因为泛型Func和Action不允许它。

答案 2 :(得分:0)

@Mark - 在您的第二个代码示例之后,您说:

  

这是一种耻辱,因为它意味着(如   据我所知,你不能   动态[重新]创建委托    ref或out 参数,因为   泛型Func和Action不允许   它

这正是我的问题,请参阅Create C# delegate type with ref parameter at runtime了解User Ani的解决方案:Expression.GetDelegateType允许参数参数。