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

2023-12-29

对于一些奇特的反射东西,我有一个 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 有什么想法吗?


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

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

EDIT:不是编译器进行转换,而是 CLR 理解这一点Func<object, bool>可以安全地投射到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 });
    }
}

EDIT 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 });
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建将一种类型的函数转换为另一种类型的函数 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • iPhone 5 (4") 底部工具栏没有响应

    我正在尝试修改一个应用程序以适应新的 iPhone 5 4 屏幕 我添加了新的启动图像 电子邮件受保护 cdn cgi l email protection 之后一切似乎都很好 我的视图的中间部分可以调整大小 但是我注意到 在有底部工具栏的
  • 获取 UIScrollView 内容的可见矩形

    我怎样才能找到屏幕上实际可见的显示视图内容的矩形 CGRect myScrollView bounds 上面的代码在没有缩放时有效 但一旦允许缩放 它就会在 1 以外的缩放比例下中断 为了澄清 我想要一个 CGRect 包含滚动视图内容相对
  • Rust:从标准输入读取和映射行并处理不同的错误类型

    我正在学习 Rust 并尝试用它解决一些基本的算法问题 在许多情况下 我想从标准输入读取行 对每行执行一些转换并返回结果项的向量 我这样做的一种方法是这样的 Fully working Rust code let my values Vec
  • Boost::Spirit 后跟默认值时字符加倍

    我使用 boost spirit 来解析单项式的 一部分 如 x y xy x 2 x 3yz 我想将单项式的变量保存到一个映射中 该映射还存储相应的指数 因此 语法还应该保存 1 的隐式指数 因此 x 存储起来就像写成 x 1 一样 st
  • 单击 R 字符串输出中的 URL

    假设我有 R 的 cat 函数的输出 它是一个 URL 例如 cat https en wikipedia org wiki Statistics Output https en wikipedia org wiki Statistics
  • 使用泛型类型时,“From”的实现如何会发生冲突?

    我正在尝试实现一个错误枚举 它可以包含与我们的特征之一相关的错误 如下所示 trait Storage type Error enum MyError
  • Python/NetworkX:动态计算边权重

    我有一个未加权的创建的图表networkx为此 我想根据边缘出现的计数 频率来计算节点之间的边缘权重 我的图中的一条边可以多次出现 但事先并不知道边出现的频率 目的是根据连接节点之间移动的权重 例如计数 频率 可视化边缘 本质上 我想创建连
  • 如何在 Tensorflow RNN 中构建嵌入层?

    我正在构建一个 RNN LSTM 网络 根据作者的年龄对文本进行分类 二元分类 年轻 成人 看起来网络没有学习并突然开始过度拟合 Red train Blue validation 一种可能是数据表示不够好 我只是按频率对独特的单词进行排序
  • 我们如何在 Julia 中上课?

    我在 Julia 中编写类时遇到问题 我查看了文档 但没有看到任何有关类的文档 例如 在 Python 中 类是 class Dog blah blah 这在朱莉娅身上怎么可能呢 朱莉娅没有课 相反 我们定义新类型 然后在这些类型上定义方法
  • 限制泛型类型参数具有特定的构造函数

    我想知道为什么对泛型类型参数的新约束只能在没有参数的情况下应用 也就是说 可以约束类型具有无参数构造函数 但不能约束类具有 比如说 一个构造函数接收一个 int 作为参数 我知道解决这个问题的方法 使用反射或工厂模式 效果很好 好吧 但我真
  • 将鼠标悬停在图像上向左移动?

    这是我的页面 http www ostmoconstruction com portfolio php http www ostmoconstruction com portfolio php 我决定更改这个小画廊中每个图像的鼠标悬停图像
  • getExternalStorageDirectory 和 getExternalStoragePublicDirectory 之间的区别?

    根据谷歌的说法 一个返回主共享 外部存储目录 另一个返回顶级共享 外部存储目录 用于放置特定类型的文件 谁能用简单的语言和例子解释一下 我假设您在生活中曾经使用过 Windows 计算机 Environment getExternalSto
  • Java 中的 try-catch 块 - catch 代码中的执行语句

    我对 Java 中 catch 块中语句的执行顺序有疑问 当我运行以下类 Test1 见下文 时 我希望首先输出 Hi 然后是 e printStackTrace 的结果 声明 然后再见 然而 我从来没有收到过这个订单 请查看我粘贴在下面的
  • 从 GraphStage 内部关闭 Akka 流 (Akka 2.4.2)

    在 Akka Stream 2 4 2 中 PushStage 已被弃用 对于 Streams 2 0 3 我使用的是这个答案中的解决方案 如何关闭 Akka 流 https stackoverflow com questions 3495
  • 如何判断文本是否适合其边界形状?

    我正在使用占位符形状和应用程序脚本将数据从谷歌电子表格合并到幻灯片演示文稿中 类似于这个例子 https developers google com slides how tos merge 我的合并运行良好 我遇到的第一个问题是文本不受包
  • 如何让 PyC​​harm 显示与 pytest 的完整错误差异?

    我在用Pycharm https www jetbrains com pycharm 运行我的pytest https docs pytest org en latest 单元测试 我正在测试 REST API 因此我经常需要验证 JSON
  • 使用python将命令的输出保存在linux中的字符串中

    我正在使用 Fedora 17 xfce 并使用 Python 2 7 3 进行编程 Fedora 使用名为 yum 的包管理器 我有一个 python 脚本 可以搜索如下所示的包 import os package raw input E
  • 如何绘制 keras 实验的学习曲线?

    我正在使用 keras 训练 RNN 并希望了解验证准确性如何随数据集大小变化 Keras 有一个名为val acc在其历史对象中 该对象在每个时期之后附加相应的验证集准确性 链接到谷歌群组中的帖子 https groups google
  • 用户控制静态名称选项?

    我知道有一种方法可以强制 asp web 用户控件 ascx 使用静态 ID 这样它们就不会附加所有附加的命名垃圾 但是有没有办法对 name 属性执行相同的操作 具体来说 在这种情况下 对于 DDL 来说 JQuery 需要一个特定的名称
  • 创建将一种类型的函数转换为另一种类型的函数

    对于一些奇特的反射东西 我有一个 Func 类型的函数 并且需要将其传递给一个接受 Func 类型的函数 其中 T 直到运行时才知道 例如 public bool MyOperation Func