c# - 将 .net Func<T> 转换为 .net Expression<Func<T>>

标签 c# .net lambda expression func

使用方法调用很容易从 lambda 转换为表达式...

public void GimmeExpression(Expression<Func<T>> expression)
{
    ((MemberExpression)expression.Body).Member.Name; // "DoStuff"
}

public void SomewhereElse()
{
    GimmeExpression(() => thing.DoStuff());
}

但我想将 Func 转换为表达式,只是在极少数情况下......

public void ContainTheDanger(Func<T> dangerousCall)
{
    try 
    {
        dangerousCall();
    }
    catch (Exception e)
    {
        // This next line does not work...
        Expression<Func<T>> DangerousExpression = dangerousCall;
        var nameOfDanger = 
            ((MemberExpression)dangerousCall.Body).Member.Name;
        throw new DangerContainer(
            "Danger manifested while " + nameOfDanger, e);
    }
}

public void SomewhereElse()
{
    ContainTheDanger(() => thing.CrossTheStreams());
}

不起作用的行给我编译时错误 Cannot implicitly convert type 'System.Func<T>' to 'System.Linq.Expressions.Expression<System.Func<T>>' .显式转换不能解决这种情况。是否有我忽略的执行此操作的工具?

最佳答案

哦,一点也不简单。 Func<T>代表一个通用的 delegate而不是一个表达。如果有任何方法可以这样做(由于优化和编译器所做的其他事情,一些数据可能会被丢弃,因此可能无法恢复原始表达式),它会即时反汇编 IL并推断表达式(这绝非易事)。将 lambda 表达式视为数据 ( Expression<Func<T>> ) 是 编译器 的魔法(基本上,编译器在代码中构建表达式树,而不是将其编译为 IL)。

相关事实

这就是为什么将 lambda 推向极致的语言(如 Lisp)通常更容易实现为解释器。在这些语言中,代码和数据本质上是同一件事(即使在运行时),但我们的芯片无法理解这种形式的代码,因此我们必须通过在其上构建解释器来模拟这样的机器理解它的人(Lisp 做出的选择,如语言)或在某种程度上牺牲能力(代码将不再完全等于数据)(C# 做出的选择)。在 C# 中,编译器允许将 lambda 解释为代码 ( Func<T> ) 和 数据 ( Expression<Func<T>> ) >编译时间。

关于c# - 将 .net Func<T> 转换为 .net Expression<Func<T>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/767733/

相关文章:

c# - 升级应用程序时安装到同一路径

c# - C# 中的 Lambda 示例

java - Kotlin 函数式接口(interface) java 兼容性

java - 检测lambda是否是方法引用

c# - .NET 框架 : Get Type from TypeInfo

c# - 在 c# 控制台应用程序中的 2 个线程之间传递变量(这里是新手)

c# - 使用 XmlNode (c#) 的相对 XPath 选择

c# - 异步并等待 For 循环

c# - 在 C# 中遍历 XML 树

c++ - 将托管函数指针作为非托管回调传递