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

亨里维尔

对于一些花哨的反射东西,我有一个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);
}

问题是,由于我有一个弱类型的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"));

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

这是我的尝试:

/// <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);

这实际上工作得很好,但是它运行非常缓慢,因为它在每次调用时都会隐式调用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);

这会导致错误:

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

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

斯威克

实际上,只要目标类型是引用类型,您就无需执行任何操作。该类型参数TFunc<T, TResult>逆变,这意味着你可以直接做演员。因此,以下代码可以正常工作:

Func<object,bool> asObject = o => o.ToString() == "a string";
Func<string,bool> asString = (Func<string,bool>)asObject;
asString("a string");

编辑:不是由编译器进行转换,而是Func<object, bool>可以安全地转换为的CLR Func<string, bool>因此,以下代码可以正常工作:

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 });
    }
}

编辑2:如果您也需要此方法用于值类型,则需要以某种方式将参数装箱。拳击本身很简单:

private static Func<T, bool> BoxParameter<T>(Func<object, bool> op)
{
    return x => op(x);
}

但是随后您需要调用它,并且由于T在编译时不知道,因此需要使用反射。就像是:

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 });
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

将一种类型转换为另一种类型

来自分类Dev

将一种类型的列表转换为另一种类型

来自分类Dev

将一种类型的 Observable 转换为另一种类型

来自分类Dev

在捕获错误时将值从一种类型转换为另一种类型的函数

来自分类Dev

如何将一种类型的CompletableFuture转换为另一种类型?

来自分类Dev

如何将嵌套对象从一种类型转换为另一种类型

来自分类Dev

C#-将异步任务从一种类型转换为另一种类型

来自分类Dev

使用已注册的lambda将一种类型转换为另一种类型的类

来自分类Dev

将每月数据从一种类型转换为另一种类型

来自分类Dev

如何将一种类型的对象(接口)转换为另一种类型(接口)?

来自分类Dev

无法将一种类型转换为另一种类型错误

来自分类Dev

如何将一种类型的对象数组转换为另一种类型?

来自分类Dev

从一种类型转换为另一种类型时的模板类型推导

来自分类Dev

在C ++中将数据从一种类型转换为另一种类型?

来自分类Dev

在c#中将一种类型转换为另一种类型

来自分类Dev

将一种类型的数据转换为另一种数据的设计模式

来自分类Dev

将一种类型的列表转换为另一种RXJava?(等效于Javascript映射)

来自分类Dev

将选项中的值转换为另一种类型

来自分类Dev

C#将ObservableCollection转换为另一种类型

来自分类Dev

是否可以将总位数相同的一种类型的位域转换为另一种类型的位域?

来自分类Dev

如何将任何类型的泛型类型转换为另一种类型

来自分类Dev

在Golang中将一个指针转换为另一种类型

来自分类Dev

一种类型的属性映射到另一种类型的实例

来自分类Dev

快速测试一种类型是否与另一种类型兼容

来自分类Dev

使用另一种类型过滤一种类型的键

来自分类Dev

向量从一种类型隐式转换为另一种c ++

来自分类Dev

使用数据库查找从另一种类型的对象创建一种类型的对象

来自分类Dev

使一种类型成为一种或另一种

来自分类Dev

在运行时将对象转换为另一种类型

Related 相关文章

  1. 1

    将一种类型转换为另一种类型

  2. 2

    将一种类型的列表转换为另一种类型

  3. 3

    将一种类型的 Observable 转换为另一种类型

  4. 4

    在捕获错误时将值从一种类型转换为另一种类型的函数

  5. 5

    如何将一种类型的CompletableFuture转换为另一种类型?

  6. 6

    如何将嵌套对象从一种类型转换为另一种类型

  7. 7

    C#-将异步任务从一种类型转换为另一种类型

  8. 8

    使用已注册的lambda将一种类型转换为另一种类型的类

  9. 9

    将每月数据从一种类型转换为另一种类型

  10. 10

    如何将一种类型的对象(接口)转换为另一种类型(接口)?

  11. 11

    无法将一种类型转换为另一种类型错误

  12. 12

    如何将一种类型的对象数组转换为另一种类型?

  13. 13

    从一种类型转换为另一种类型时的模板类型推导

  14. 14

    在C ++中将数据从一种类型转换为另一种类型?

  15. 15

    在c#中将一种类型转换为另一种类型

  16. 16

    将一种类型的数据转换为另一种数据的设计模式

  17. 17

    将一种类型的列表转换为另一种RXJava?(等效于Javascript映射)

  18. 18

    将选项中的值转换为另一种类型

  19. 19

    C#将ObservableCollection转换为另一种类型

  20. 20

    是否可以将总位数相同的一种类型的位域转换为另一种类型的位域?

  21. 21

    如何将任何类型的泛型类型转换为另一种类型

  22. 22

    在Golang中将一个指针转换为另一种类型

  23. 23

    一种类型的属性映射到另一种类型的实例

  24. 24

    快速测试一种类型是否与另一种类型兼容

  25. 25

    使用另一种类型过滤一种类型的键

  26. 26

    向量从一种类型隐式转换为另一种c ++

  27. 27

    使用数据库查找从另一种类型的对象创建一种类型的对象

  28. 28

    使一种类型成为一种或另一种

  29. 29

    在运行时将对象转换为另一种类型

热门标签

归档