我在c#中编写表达式树的第一次尝试并不太顺利:)。这是我试图复制的c#代码
public static object Test<S, D>(S source, Func<D, object> selector )
where S : class
where D : class
{
D derived = source as D;
object retVal = null;
if( derived != null ) retVal = selector(derived);
return retVal;
}
从概念上讲,这是为了获取一个对象并对其应用一个选择器,以便在所提供的对象属于派生类时返回派生类的属性。
这是我到目前为止所得到的:
public static object OrderByDerivedProperty<S>( S source, Type derivedType, string fieldName )
{
ParameterExpression parameter = Expression.Parameter(typeof(S), "source");
UnaryExpression typeAs = Expression.TypeAs(parameter, derivedType);
ConstantExpression nullConst = Expression.Constant(null);
BinaryExpression isNotNull = Expression.NotEqual(typeAs, nullConst);
ParameterExpression varDest = Expression.Variable(derivedType, "varDest");
ParameterExpression retVal = Expression.Variable(typeof(object), "retVal");
BlockExpression block = Expression.Block(
new[] { varDest, retVal },
Expression.Assign(varDest, typeAs),
Expression.Condition(
isNotNull,
Expression.Assign(retVal, Expression.Property(varDest, fieldName)),
Expression.Assign(retVal, nullConst)
),
retVal
);
LambdaExpression lambda = Expression.Lambda(block, new[] { parameter });
return lambda.Compile().DynamicInvoke(source);
}
我在这里使用了一些不同的参数来简化我的表达式。
当derivedType实际上是从S派生的Type时,代码可以工作。但是,如果不是 - 当我期望代码返回retVal = null时 - 它会在以下行中爆炸:
Expression.Assign(retVal, Expression.Property(varDest, fieldName)),
抱怨fieldName不是varDest的属性。在这种情况下哪个是正确的......但是我期待如果测试表达式为假,则不会评估Condtional表达式的“if true”组。事实显然并非如此。
我不知道表达树会填满(超过)一本书。但如果有人能指出我要离开的地方,我会很感激。
答案 0 :(得分:0)
不确定你是否得到了这个答案,但这就是你需要的
public static object OrderByDerivedProperty<TSource>(TSource source, Type derivedType, string propertyOrFieldName)
{
if (!derivedType.IsClass)
{
throw new Exception("Derived type must be a class.");
}
ParameterExpression sourceParameter = Expression.Parameter(typeof(object), "source");
ParameterExpression typeAsVariable = Expression.Variable(derivedType);
ParameterExpression returnVariable = Expression.Variable(typeof(object));
BlockExpression block = Expression.Block(
new[] { typeAsVariable,returnVariable },
Expression.Assign(
typeAsVariable,
Expression.TypeAs(
sourceParameter,
derivedType
)
),
Expression.Condition(
Expression.NotEqual(
typeAsVariable,
Expression.Constant(
null,
derivedType
)
),
Expression.Assign(
returnVariable,
Expression.Convert(
Expression.PropertyOrField(
typeAsVariable,
propertyOrFieldName
),
typeof(object)
)
),
Expression.Assign(
returnVariable,
Expression.Constant(
null,
typeof(object)
)
)
),
returnVariable
);
var lambda = Expression.Lambda<Func<object,object>>(block, new[] { sourceParameter });
return lambda.Compile().Invoke(source);
}