我有一个表达式,我想再插入一个节点。我发现了this SO question类似的问题,它在表达式的末尾添加了一个属性。 我对Expressions很陌生,我不知道在节点之间做什么。
我做了这个简单的控制台测试应用程序来显示我遇到的问题:
public class Program
{
private static void Main()
{
var provider = new Provider<Foo>();
var foo = new Foo {Label = "myLabel", Owner = "Me"};
provider.AddData(foo);
provider.AddExpression(f => f.Label);
// This writes: f => f.Label
Console.WriteLine(provider.OriginalExpression.ToString());
// This should write: f => f.WrappedData.Label
// At the moment it writes: NULL
Console.WriteLine(provider.WrapperExpression == null ? "NULL" : provider.WrapperExpression.ToString());
Console.ReadKey();
}
}
public class Foo
{
public string Label { get; set; }
public string Owner { get; set; }
}
public class Wrapper<T> where T : class
{
public string Id { get; set; }
public T WrappedData { get; set; }
}
public class Provider<T> where T : class
{
public Wrapper<T> _internalWrapper = new Wrapper<T>();
// The expression for the Property when using T (i.e. Foo)
public Expression<Func<T, string>> OriginalExpression { get; private set; }
// The expression for the Property when using _internalWrapper
public Expression<Func<Wrapper<T>, string>> WrapperExpression { get; private set; }
public void AddData(T data)
{
_internalWrapper = new Wrapper<T> { WrappedData = data, Id = "myId" };
}
public void AddExpression(Expression<Func<T, string>> valueExpression)
{
OriginalExpression = valueExpression;
BuildWrapperExpression();
}
private void BuildWrapperExpression()
{
// HERE IS THE PROBLEM:
// Here I have to insert the node "WrappedData" in the OriginalExpression and save it as WrapperExpression
// So {f => f.Label} must result into {f => f.WrappedData.Label}
// It should work as well for deeper nodes. I.e. when OriginalExpression is something like {f => f.Bar.Prop2.Label}
}
}
我已经在BuildWrapperExpression()方法中尝试了一个视图版本,但没有一个提供f => f.WrappedData.Label
。
我得到类似的东西
f => Invoke(value (ConsoleApplication1.Provide1+<>c__DisplayClass1[ConsoleApplication1.Foo]).lambda, f.WrappedData)
或
x => Invoke(f => f.Label, Invoke(e => e.WrappedData, x))
因为我对表达式的进一步使用必须是x => x.WrappedData.Label
非常感谢你们
答案 0 :(得分:1)
不能简单地说:
private void BuildWrapperExpression()
{
var lambda = OriginalExpression.Compile();
WrapperExpression = x => lambda(x.WrappedData);
}
或者,您可以实现ExpressionVistor。检查Marc的答案:https://stackoverflow.com/a/9132775/1386995
答案 1 :(得分:1)
我使用Nikita提供的链接找到了一个很好的解决方案。
我正在使用这个新课程ExpressionChainer
:
public static class ExpressionChainer
{
public static Expression<Func<TOuter, TInner>> Chain<TOuter, TMiddle, TInner>(
this Expression<Func<TOuter, TMiddle>> left, Expression<Func<TMiddle, TInner>> right)
{
return ChainTwo(left, right);
}
public static Expression<Func<TOuter, TInner>> ChainTwo<TOuter, TMiddle, TInner>(
Expression<Func<TOuter, TMiddle>> left, Expression<Func<TMiddle, TInner>> right)
{
var swap = new SwapVisitor(right.Parameters[0], left.Body);
return Expression.Lambda<Func<TOuter, TInner>>(
swap.Visit(right.Body), left.Parameters);
}
private class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
}
然后我要做的就是:
private void BuildWrapperExpression()
{
Expression<Func<Wrapper<T>, T>> expression = x => x.WrappedData;
WrapperExpression = expression.Chain(OriginalExpression);
}
其中x => x.WrappedData.Label
为WrapperExpression