使用方法调用从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>>)是compiler的魔术(基本上编译器在代码中构建表达式树,而不是将其编译为IL).

相关事实

这就是将lambdas推到极致的语言(如Lisp)通常更容易实现为interpreters的原因.在这些语言中,代码和数据本质上是一回事(即使是在run time),但是我们的芯片不能理解这种代码形式,因此我们必须模拟这样的机器,在其之上构建一个能够理解它的解释器(Lisp做出的 Select 类似于语言),或者在某种程度上牺牲功能(代码将不再完全等于数据)(C#做出的 Select ).在C#中,编译器允许lambda在compile time被解释为code(Func<T>)和data(Expression<Func<T>>),从而给人一种将代码视为数据的错觉.

.net相关问答推荐

为什么$NULL在ForEach-Object{}和Foreach()中的行为不同?

.NET restore/build在使用组织包的Github Action工作流中调用时获得401

跨请求共享数据

Visual Studio 2022 中的目标操作系统和目标运行时有什么区别?

是否存在指定的(子)索引分隔符?

如何在 MSBuild 脚本中获取当前目录?

为什么 .NET 内部 Hashtable 中有一个 Thread.Sleep(1)?

重新启动(回收)应用程序池

如何通过 LINQ 比较没有时间的 DateTime?

Microsoft.Practices.ServiceLocation 来自哪里?

ASP.NET Core 等效于 ASP.NET MVC 5 的 HttpException

在 C# 中使用委托

ObservableCollection<> 与 List<>

风格上的差异:IDictionary vs Dictionary

如何在 WPF 中的 Xaml 文件中添加注释?

如何从其十六进制 RGB 字符串创建 System.Drawing.Color?

嵌套的 Try/Catch 块是个坏主意吗?

为什么 .NET 中没有 Tree 类?

如何从 HashSet 中检索实际项目?

如何将 VB 项目转换为 C# 项目