【问题标题】:Serialize an expression with an variable用变量序列化表达式
【发布时间】:2011-12-09 16:04:00
【问题描述】:

我编写了一些类来将System.Linq.Expressions 序列化为 DataContracts,以便能够通过 WCF 发送。它工作得很好很好。问题是当我想序列化一个包含变量的表达式时。这是一个解释问题的例子:

public class Foo
{
    public string Name { get; set; }
}

// CASE 1
Expression<Func<Foo, bool>> lambda = foo => foo.Name == "Test";
Console.WriteLine(lambda);
// OUTPUT: foo => (foo.Name == "Test")

// CASE 2
var variable = "Test";
lambda = foo => foo.Name == variable;            
this.AssertExpression(lambda, "Class Lambda expression with variable.");
// OUTPUT: foo => (foo.Name == value(MyTest+<>c__DisplayClass0).variable)

序列化CASE 2表达式没有问题,但是序列化的数据没有用,因为在服务端,没有什么可以解决value(MyTest+&lt;&gt;c__DisplayClass0).variable

所以我需要在序列化该表达式之前解析变量,以便 CASE 2 表达式序列化为与 CASE1 相同的结果

【问题讨论】:

  • 出于完全不同的原因,我有一个类似的问题表达。长话短说,在遍历树检查成员访问时,如果该成员不是表达式的 TSource,则向下钻取到成员中的值并将其放在常量中。现在没有时间对此进行扩展,但希望您能走上正轨。如果您需要我扩展,请告诉我,我会做出正确的回答... GL!编辑:我对此提出了一个问题,因此如果您对它们进行扫描,您可能会找到参考代码-出于某种原因,我相信它们的排名为-1

标签: c# linq lambda linq-expressions


【解决方案1】:

对不起 VB,但是下面的摘录是我在评论中的意思。我不认为它涵盖了所有基础 (即它可能没有深入研究,所以请确保你测试它) 但对于 simple 大多数示例它都有效:

代码基于this MSDN Expression Visitor example:

class CustomExpressionWalker<TSource> : ExpressionVisitor
{
    protected override Expression VisitMemberAccess(MemberExpression m)
    {
        if (m.Member.DeclaringType != typeof(TSource))
        {
            // We are accessing a member/variable on a class
            // We need to descend the tree through the navigation properties and eventually derive a constant expression
            return this.VisitMemberAccess(m, m.Type);
        }
        throw new NotImplementedException();
    }

    protected Expression VisitMemberAccess(MemberExpression m, Type expectedType)
    {
        if (m.Expression.NodeType == ExpressionType.Constant)
        {
            // We are at the end of the member expression 
            // i.e. MyClass.Something.Something.Value <-- we're at the Value part now
            ConstantExpression constant = (ConstantExpression)m.Expression;
            return Expression.Constant(m.Expression.Type.GetFields().Single(n => n.FieldType == expectedType && m.Member.Name.Contains(n.Name)).GetValue(constant.Value));
        }
        else if (m.Member.DeclaringType == typeof(TSource))
        {
            // I'm unsure of your current implementation but the original Member access
            // regarding serializing the expression, but if the code reaches here a nested
            // MemberAccess has landed on a Property/variable of type TSource, so you'll need
            // to decide whether to serialize here or not.  For example, if TSource was of 
            // type "myClass", it could be 
            // (myOtherClass x) => x.myClass
            throw new NotImplementedException();
        }
        else if (m.Member.DeclaringType == typeof(Nullable))
        {
            // never got round to implementing this as we don't need it yet
            // if you want to deal with Nullable<T> you're going to have to 
            // examine the logic here
            throw new NotImplementedException();
        }
        else
        {
            // continue walking the member access until we derive the constant
            return this.VisitMemberAccess((MemberExpression)m.Expression, expectedType);
        }
    }
}   

希望这会有所帮助!

编辑:The original issue I had 是当 MemberAccess 不是 TSource 类时我没有继续走树,上面的逻辑实际上应该递归地根除这些情况,所以忽略我原来的评论。我留在了Nullable&lt;T&gt; 子句(在 else if 语句中,因为我认为现有的逻辑不会涵盖这些情况,它也可能会遇到困难使用泛型类。

也就是说,这应该让你处于有利地位。如果您没有使用 Expression Visitor,您能否提供更多详细信息/代码?

祝你好运!

【讨论】:

  • 谢谢,在我删除了n.FieldType == expectedType 之后,这几乎搞定了。
猜你喜欢
  • 1970-01-01
  • 2014-06-08
  • 2016-10-17
  • 1970-01-01
  • 2020-03-20
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
  • 2010-09-18
相关资源
最近更新 更多