连接具有多个参数的委托属性和具有对象[]类型的单个参数的方法

本文关键字:参数 类型 单个 方法 对象 连接 属性 | 更新日期: 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。

但我仍然希望找到一个更简单的解决方案。