我正在尝试构建一个表达式树,但它在编译时抛出 NotSupportedException:
TryExpression is not supported as an argument to method 'Boolean TryGetMemberValue(System.Object, System.String, System.Object ByRef)' because it has an argument with by-ref type. Construct the tree so the TryExpression is not nested inside of this expression.
我有点明白它说的是什么,但我不知道我需要改变什么......这是代码:
static void Main()
{
//A.Child.Name
var child = CreateExpression("Child", proxyParameter);
var name = CreateExpression("Name", child);
var expr = Expression.Lambda<Func<Proxy, object>>(name, proxyParameter);
var func = expr.Compile();
}
class A
{
public A Child { get; set; }
public string Name { get; set; }
}
abstract class Proxy
{
public abstract bool TryGetMemberValue(object parent, string name, out object result);
}
static ParameterExpression proxyParameter = Expression.Parameter(typeof(Proxy), "proxy");
static Expression CreateExpression(string propertyName, Expression parent)
{
var tryGetMemberMethod = typeof(Proxy).GetMethod("TryGetMemberValue");
var result = Expression.Variable(typeof(object), "out result");
var returnTarget = Expression.Label(typeof(object));
var tryGetMember =
Expression.Block(
new[] { result },
Expression.IfThenElse(Expression.Equal(Expression.Call(proxyParameter, tryGetMemberMethod, parent, Expression.Constant(propertyName), result), Expression.Constant(true)),
Expression.Return(returnTarget, result),
Expression.Throw(Expression.Constant(new MissingMemberException(propertyName)))),
Expression.Label(returnTarget, Expression.Constant(null)));
return tryGetMember;
}
生成以下表达式:
.Lambda #Lambda1<System.Func`2[Program+Proxy,System.Object]>(Program+Proxy $proxy) {
.Block(System.Object $'out result') {
.If (.Call $proxy.TryGetMemberValue(
.Block(System.Object $'out result') {
.If (.Call $proxy.TryGetMemberValue(
$proxy,
"Child",
$'out result') == True) {
.Return #Label1 { $'out result' }
} .Else {
.Throw .Constant<System.MissingMemberException>(System.MissingMemberException: Child)
};
.Label
null
.LabelTarget #Label1:
},
"Name",
$'out result') == True) {
.Return #Label2 { $'out result' }
} .Else {
.Throw .Constant<System.MissingMemberException>(System.MissingMemberException: Name)
};
.Label
null
.LabelTarget #Label2:
}
有什么想法吗?
/* 已编辑 */ 有趣的是,这工作得很好:
var tryGetMember =
Expression.Block(
new[] { result },
Expression.Call(proxyParameter, tryGetMemberMethod, parent, Expression.Constant(propertyName), result),
result);
最佳答案
虽然异常消息还不清楚,但我认为您刚刚遇到了 Expression
编译器的限制:在带有 ref 的方法的调用表达式下不能有复杂的子表达式
参数。
我认为解决这个问题的方法基本上与在 C# 代码中执行的操作相同:使用局部变量来保留中间结果:
var child = Expression.Variable(typeof(object), "child");
var body = Expression.Block(
new[] { child },
Expression.Assign(child, CreateExpression("Child", proxyParameter)),
CreateExpression("Name", child));
var expr = Expression.Lambda<Func<Proxy, object>>(body, proxyParameter);
通过此更改,代码不再引发异常。
此外,您不需要在 tryGetMember
表达式中使用 Label
和 Return
。相反,您可以将 IfThenElse
替换为 Condition
(基本上是 C# 中的三元运算符)。如果这样做,您还需要指定 Throw
的类型(即使它从未实际返回):
var tryGetMember =
Expression.Block(
new[] { result },
Expression.Condition(
Expression.Equal(
Expression.Call(
proxyParameter, tryGetMemberMethod, parent,
Expression.Constant(propertyName), result),
Expression.Constant(true)),
result,
Expression.Throw(
Expression.Constant(new MissingMemberException(propertyName)),
typeof(object))));
关于c# - 构建表达式树抛出 NotSupportedException "TryExpression is not supported as an argument to method..",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19625232/