如何在运行时定义委托类型(即动态委托类型)
对于实时创建委托,技术因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是创建一个新的委托它等同于原来的委托,但对这一个新的第一个参数...即一个开放的版本与之前关闭的代表。
有没有一种简单的方法来克隆&修改现有委托类型,或者是打造出来的通用函数功能<>和行动<>类型最接近的解决方案?
@马克 - 你的第二个代码示例后,你说:
这是一种耻辱,因为这意味着(如 据我可以告诉),你不能 动态[重新]创建代表 ref或out自变量,因为 泛型Func和Action将不允许 它。
这正是我的问题,请参阅Create C# delegate type with ref parameter at runtime来自User Ani的解决方案:Expression.GetDelegateType
允许ref参数。
具有不同签名的新代表是一种新类型。 C#是类型安全的,它不可能做到这一点 - 除了搅动一些代码并在运行时编译外,除了内存泄漏之外并不是这样一种优雅的方法。
但是你可以做的是根据委托类型从已经完成的动作<>或Func <>中选择适当的委托。或者,根据您的预期类型创建一个您自己的LITS,并在运行时选择它。
一点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]用ref或out参数创建委托,因为泛型Func和Action不允许它。