创建将一种类型的函数转换为另一种类型的函数

对于一些花哨的reflection内容,我有一个类型为Func的函数,需要将它传递给一个接受Func类型的函数,其中T在运行时才知道。 例如:

public bool MyOperation(Func op) { return _myValues.Any(op); } public static bool InvokeOperationMethod(MethodInfo info, object obj,Func opAsObject) { info.Invoke(obj, opAsObject); } 

问题在于,由于我有一个较弱类型的lambda,我不能将它作为更强类型的参数传递。 所以我尝试创建一个帮助程序,它将创建一个将较弱类型的lambda转换为更强类型的函数。 例如,我可以打电话

 var converter = CreateConverter(typeof(string)); Func asObject = o => o.ToString() == "a string"; //Dump example Func asString = (Func)converter(asObject); Assert.IsTrue(asInt("a string")); 

当然在实际代码中,目标类型直到运行时才知道,而实际谓词不是一些简单的测试。

这是我的尝试:

 ///  /// Converts a predicate of Func to /// Func of the given type. ///  /// Type of the dest. /// The predicate. ///  public static TransformPredicate CreateConverter(Type destType) { // This essentially creates the following lambda, but uses destType instead of T // private static Func<Func, Func> Transform() // { // return (Func input) => ((T x) => input(x)); // } var input = Expression.Parameter(typeof(Func), "input"); var x = Expression.Parameter(destType, "x"); var convert = Expression.Convert(x, typeof(object)); var callInputOnX = Expression.Invoke(input, convert); var body2 = Expression.Lambda(callInputOnX, x); var body1 = Expression.Lambda(typeof(TransformPredicate),body2, input); return (TransformPredicate) body1.Compile(); } public delegate object TransformPredicate(Func weak); 

这实际上运行得很好,除了它运行得非常慢,因为它在每次调用时隐式调用CreateDelegate。 所以我尝试通过添加以下内容来调用CreateDelegate:

 var destFunc = typeof(Func).MakeGenericType(destType, typeof(bool)); var endType = typeof(Func).MakeGenericType(typeof(Func), destFunc); return (TransformPredicate)compiled.Method.CreateDelegate(endType); 

这会导致错误:

System.NotSupportedException:派生类必须提供和实现。

我有什么想法可以自己调用CreateDelegate吗?

实际上,只要目标类型是引用类型,您就不必执行任何操作。 Func的类型参数T逆变的 ,这意味着你可以直接进行转换。 因此,以下代码工作正常:

 Func asObject = o => o.ToString() == "a string"; Func asString = (Func)asObject; asString("a string"); 

编辑:这不是编译器进行转换,它是CLR,它理解Func可以安全地转换为Func 。 因此,以下代码将正常工作:

 class Program { static void Main() { InvokeOperationMethod( typeof(Program).GetMethod("MyOperation"), new Program(), o => o.ToString() == "42"); } public bool MyOperation(Func op) { return op("43"); } public static bool InvokeOperationMethod( MethodInfo info, object obj, Func opAsObject) { return (bool)info.Invoke(obj, new object[] { opAsObject }); } } 

编辑2:如果你需要这个也适用于值类型,你需要以某种方式打包参数。 拳击本身很简单:

 private static Func BoxParameter(Func op) { return x => op(x); } 

但是你需要调用它,因为你在编译时不知道T ,你需要使用reflection。 就像是:

 public static bool InvokeOperationMethod( MethodInfo method, object obj, Func opAsObject) { var targetType = method.GetParameters() .Single() .ParameterType .GetGenericArguments()[0]; object opAsT; if (targetType.IsValueType) { opAsT = typeof(Program).GetMethod("BoxParameter", BindingFlags.NonPublic | BindingFlags.Static) .MakeGenericMethod(targetType) .Invoke(null, new object[] {opAsObject}); } else { opAsT = opAsObject; } return (bool)method.Invoke(obj, new[] { opAsT }); }