将.net Func <T>转换为.net表达式<Func <T >>
使用方法调用从lambda转换为Expression很容易...
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)通常更容易作为解释器来实现。 在这些语言中,代码和数据本质上是相同的(即使在运行时),但是我们的芯片无法理解这种形式的代码,所以我们必须通过在其上构建一个理解它的解释器来模拟这种机器或者牺牲功能(代码将不再完全等同于数据)在某种程度上(由C#所做的选择)。 在C#中,编译器通过允许lambda在编译时被解释为代码 ( Func<T>
)和数据 ( Expression<Func<T>>
),给出了将代码视为数据的错觉。
你可能应该做的,就是改变方法。 进入表达式>,然后编译并运行。 如果失败了,你已经有了表达式。
public void ContainTheDanger(Expression<Func<T>> dangerousCall)
{
try
{
dangerousCall().Compile().Invoke();;
}
catch (Exception e)
{
// This next line does not work...
var nameOfDanger =
((MemberExpression)dangerousCall.Body).Member.Name;
throw new DangerContainer(
"Danger manifested while " + nameOfDanger, e);
}
}
public void SomewhereElse()
{
ContainTheDanger(() => thing.CrossTheStreams());
}
显然你需要考虑这个的性能影响,并确定它是否是你真正需要做的事情。
private static Expression<Func<T, bool>> FuncToExpression<T>(Func<T, bool> f)
{
return x => f(x);
}
链接地址: http://www.djcxy.com/p/31591.html
上一篇: converting a .net Func<T> to a .net Expression<Func<T>>