2010-10-27 104 views
2

对于实时创建委托,技术因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是创建一个新的委托它等同于原来的委托,但对一个新的第一个参数...即一个开放的版本与之前关闭的代表。

有没有一种简单的方法来克隆&修改现有委托类型,或者是打造出来的通用函数功能<>和行动<>类型最接近的解决方案?

回答

0

@马克 - 你的第二个代码示例后,你说:

这是一种耻辱,因为这意味着(如 据我可以告诉),你不能 动态[重新]创建代表 ref或out自变量,因为 泛型Func和Action将不允许 它。

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

1

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

但是你可以做的是根据委托类型从已经完成的动作<>或Func <>中选择适当的委托。或者,根据您的预期类型创建一个您自己的LITS,并在运行时选择它。

1

一点experiemntation后,我发现下面的代码大约是最好的方式来实现我所期待的:

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

这是一种耻辱,因为这意味着(据我可以告诉),因为泛型Func和Action不允许动态地[re]用refout参数创建委托,因为泛型Func和Action不允许它。