连接具有多个参数的委托属性和具有对象[]类型的单个参数的方法
本文关键字:参数 类型 单个 方法 对象 连接 属性 | 更新日期: 2023-09-27 18:24:42
在某个对象中,我有一个委托属性,其中有几个通过反射获得的调用参数。例如:
public Action<int,double,DateTime> myDel{get;set;}
所以我只有关于它的反射信息
PropertyInfo del = FindDelegate();
var adel = del.PropertyType;//Type of Delegate
var ainvk = adel.GetMethod ("Invoke");//Invoke Method Info
我有一个签名的方法:
public void MyMeth(object[] args){/*...*/}
在调用Delegate myDel时,我需要调用此方法。问题是,我通过反射得到一个委托,它的输入参数的数量和类型都是变量。
有没有什么方法可以在不使用C#中的EMIT的情况下解决它?那么C#4呢?非常感谢。
这个世界上没有什么是不可能的。。。但是有一些限制。
我找到了一个解决方案,但这是我写过的最奇怪的代码。
目标是创建一个工厂,生产与原始委托具有相同签名的委托。每个生成委托都将调用一个简单的操作,将其输入参数转换为对象[],然后调用方法«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#得到了一个具有多达16个泛型参数的泛型委托类型"Action"家族。你见过一个有超过16个输入参数的方法吗?我希望不会。所以具有相应通用实现的Action对象对这个工厂来说是一个很好的输出。
另一方面,C#可以通过Activator:产生不同的通用类型
var genericType = typeof(SomeType<>).MakeGenericTypeDefinition(Type[] argTypes);
var myObj = Activator.CreateInstance(genericType) as IMyInterface;
但以这种方式创建动作对象几乎是不可能的。相反,我可以为每个Action泛型类型创建一个泛型子工厂。所有这些子工厂都实现了非通用接口:
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。无发射。但子工厂的实施规模约为140条生产线。
同样的技术也适用于具有返回类型的委托。在这种情况下,您应该使用Func类型而不是操作,并更正Factory和SubFactory。
但我仍然希望找到一个更简单的解决方案。