代码之家  ›  专栏  ›  技术社区  ›  Mark

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

  •  3
  • Mark  · 技术社区  · 15 年前

    对于动态创建委托,技术从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);
         }
    }
    

    上述代码的目的是创建一个新的委托,该委托与原始委托相同,但具有新的第一个参数 …即以前关闭的委托的打开版本。

    是否有一种简单的方法来克隆和修改现有的委托类型,或者是最近的解决方案来构建通用的func<>和action<>类型?

    3 回复  |  直到 14 年前
        1
  •  0
  •   Community Mohan Dere    8 年前
        2
  •  1
  •   Aliostad    15 年前

        3
  •  1
  •   Mark    15 年前

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