这个世界上没有不可能的事……但有一些限制。
我找到了一个解决方案,但这是我写过的最奇怪的代码。
目标是创建一个工厂,生成一个与原始委托具有相同签名的委托。每个生产委托都会调用一个简单的操作,将其输入参数转换为 object[],然后调用方法«MyMeth»:
static Delegate MagicFactory(Action<object[]> callingMehod, Type[] ArgsTypes){/**/}
我们通过这个魔法工厂得到了明确的解决方案:
PropertyInfo del = FindDelegate(); //Got an original delegate property
var adel = del.PropertyType; //Got an original deleagate type
var ainvk = adel.GetMethod ("Invoke"); //Got an invoke method of original delegate
var types = ainvk.GetParameters ()
.Select (p => p.ParameterType)
.ToArray (); //delegate arguments types
//Our magic factory:
var delegateHandler = HeavyReflectionTools.MagicFactory(MyMeth, types);
//Converting produced delegate to original delegate type:
var convertedHandler = Delegate.CreateDelegate (adel, delegateHandler, "Invoke");
//Set produced delegate to original property:
del.SetValue (Contract, convertedHandler, null);
但是这个工厂的代码很奇怪……如果你有更简单的解决方案,请告诉我。
我的解决方案:
首先,C# 获得了一个泛型委托类型“Action”系列,其中包含多达 16 个泛型参数。你见过有超过 16 个输入参数的方法吗?我希望没有。因此,具有相应通用实现的 Action 对象对于这个工厂来说是一个很好的输出。
另一方面,C# 可以通过 Activator 生成不同的泛型类型:
var genericType = typeof(SomeType<>).MakeGenericTypeDefinition(Type[] argTypes);
var myObj = Activator.CreateInstance(genericType) as IMyInterface;
但是以这种方式创建动作对象几乎是不可能的。相反,我可以为每个 Action 泛型类型创建一个泛型 Sub 工厂。所有这些子工厂都实现了非通用接口:
interface IDelegateSubFactory{
Delegate GetActionConverter (Action<object[]> act);
}
所以会有 16 个子工厂具有不同的泛型实现,每个对应的 Action 泛型实现一个:
(It is not a code)
class SubFactory<T>: IDelegateSubFactory -> Action<T>
class SubFactoty<T1,T2>: IDelegateSubFactory -> Action<T1,T2>
class SubFactoty<T1,T2,T3>: IDelegateSubFactory -> Action<T1,T2,T3>
/*...*/
class SubFactoty<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>: IDelegateSubFactory -> Action< <T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>
每个子工厂都非常简单:
class SubFactoty <T1,T2,T3>: IDelegateSubFactory{
public Delegate GetActionConverter (Action<object[]> act){
Action<T1,T2,T3> ans = (t1,t2,t3)=> act(new object[]{t1,t2,t3});
return ans;
}
}
class SubFactoty <T1,T2,T3,T4>: IDelegateSubFactory{
public Delegate GetActionConverter (Action<object[]> act){
Action<T1,T2,T3,T4> ans = (t1,t2,t3,t4)=> act(new object[]{t1,t2,t3,t4});
return ans;
}
}
我终于可以填满魔法工厂的尸体了:
static Delegate MagicFactory(Action<object[]> action, Type[] types){
Type t = null;
switch (types.Length){
case 0: return new Action(()=>action(new object[0]));
case 1: t = typeof(SubFactory <,>); break;
case 2: t = typeof(SubFactory <,>); break;
case 3: t = typeof(SubFactory <,,>); break;
case 4: t = typeof(SubFactory <,,,>); break;
case 5: t = typeof(SubFactory <,,,,>); break;
/*...*/
case 16: t = typeof(SubFactory <,,,,,,,,,,,,,,,>); break;
default: throw new Exception("Cannot handle a method with more than 16 arguments. Try to use complex object instead");
}
var gt = t.MakeGenericType (types);
var gen = Activator.CreateInstance (gt) as IDelegateSubFactory;
return gen.GetActionConverter (action);
}
这也适用于 C# 3 和 CompactFramework。没有发射。但 SubFactories 实现的大小约为 140 行。
同样的技术也适用于具有返回类型的委托。在这种情况下,您应该使用 Func 类型而不是 action,并更正 Factory 和 SubFactories。
但我还是希望能找到更简单的解决方案。