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

C# 创建将一种类型的函数转换为另一种类型的函数,c#,reflection,expression-trees,C#,Reflection,Expression Trees,对于一些奇特的反射,我有一个Func类型的函数,需要将它传递到一个接受Func类型的函数中,其中T直到运行时才知道。例如: public bool MyOperation(Func<string,bool> op) { return _myValues.Any(op); } public static bool InvokeOperationMethod(MethodInfo info, object obj,Func<object,bool> opAsObject

对于一些奇特的反射,我有一个Func类型的函数,需要将它传递到一个接受Func类型的函数中,其中T直到运行时才知道。例如:

public bool MyOperation(Func<string,bool> op) {
  return _myValues.Any(op);
}

public static bool InvokeOperationMethod(MethodInfo info, object obj,Func<object,bool> opAsObject)
{
   info.Invoke(obj, opAsObject);
}
public bool MyOperation(函数操作){
返回_myValues.Any(op);
}
公共静态bool InvokeOperationMethod(MethodInfo、object obj、Func opAsObject)
{
信息调用(对象、对象);
}
问题是,因为我有一个较弱类型的lambda,所以我不能将它作为一个更强类型的参数传递。因此,我尝试创建一个助手,它将创建一个函数,将较弱类型的lambda转换为较强类型。例如,我可以打电话

var converter = CreateConverter(typeof(string));
Func<object,bool> asObject = o => o.ToString() == "a string"; //Dump example
Func<string,bool> asString = (Func<string,bool>)converter(asObject);
Assert.IsTrue(asInt("a string"));
var converter=CreateConverter(typeof(string));
Func asObject=o=>o.ToString()=“一个字符串”//转储示例
Func asString=(Func)转换器(asObject);
Assert.IsTrue(asInt(“字符串”));
当然,在实际代码中,直到运行时才知道目标类型,并且实际谓词不是一些简单的测试

这是我的尝试:

/// <summary>
/// Converts a predicate of Func<object,bool> to
/// Func<Type,bool> of the given type.
/// </summary>
/// <param name="destType">Type of the dest.</param>
/// <param name="predicate">The predicate.</param>
/// <returns></returns>
public static TransformPredicate CreateConverter(Type destType)
{
    // This essentially creates the following lambda, but uses destType instead of T
    // private static Func<Func<object, bool>, Func<T, bool>> Transform<T>()
    // { 
    //     return (Func<object,bool> input) => ((T x) => input(x));
    // }
    var input = Expression.Parameter(typeof(Func<object, bool>), "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<object,bool> weak);
//
///将Func的谓词转换为
///给定类型的Func。
/// 
///目的地的类型。
///谓词。
/// 
公共静态转换器(类型destType)
{
//这实际上创建了以下lambda,但使用destType而不是T
//私有静态Func变换()
// { 
//返回(函数输入)=>((tx)=>输入(x));
// }
变量输入=表达式参数(typeof(Func),“输入”);
var x=表达式参数(destType,“x”);
var convert=Expression.convert(x,typeof(object));
var callInputOnX=Expression.Invoke(输入,转换);
var body2=表达式λ(callInputOnX,x);
var body1=Expression.Lambda(typeof(TransformPredicate),body2,input);
返回(TransformPredicate)body1.Compile();
}
公共委托对象转换谓词(Func弱);
这实际上工作得很好,只是它运行得非常慢,因为它在每次调用时都隐式调用CreateDelegate。因此,我尝试通过添加以下内容来调用CreateDelegate:

var destFunc = typeof(Func<,>).MakeGenericType(destType, typeof(bool));
var endType = typeof(Func<,>).MakeGenericType(typeof(Func<object, bool>), destFunc);
return (TransformPredicate)compiled.Method.CreateDelegate(endType);
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<object,bool> asObject = o => o.ToString() == "a string";
Func<string,bool> asString = (Func<string,bool>)asObject;
asString("a string");

这可能会有帮助,我不明白。为什么不能直接调用
对象(“字符串”)
?我认为这关系到你将如何准确地使用结果,因此如果你展示出来,这将有所帮助。我试图澄清我需要在反射中发生什么,以及为什么我需要实际制作一个转换器,而不是依赖编译器来为我进行转换。你是对的。我忘了我需要它的原因是,有时目标类型不是by-ref。有什么办法吗?我一直对object和by-ref类型之间的关系感到困惑,因为我可以这样做:objecto=1;o、 Dump();
class Program
{
    static void Main()
    {
        InvokeOperationMethod(
            typeof(Program).GetMethod("MyOperation"),
            new Program(), o => o.ToString() == "42");
    }

    public bool MyOperation(Func<string, bool> op)
    {
        return op("43");
    }

    public static bool InvokeOperationMethod(
        MethodInfo info, object obj, Func<object, bool> opAsObject)
    {
        return (bool)info.Invoke(obj, new object[] { opAsObject });
    }
}
private static Func<T, bool> BoxParameter<T>(Func<object, bool> op)
{
    return x => op(x);
}
public static bool InvokeOperationMethod(
    MethodInfo method, object obj, Func<object, bool> 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 });
}