为了动态创建代理,技术各不相同,从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;类型?
答案 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
允许参数参数。