使用变量序列化表达式

发布于 2024-12-20 13:33:18 字数 786 浏览 0 评论 0原文

我编写了一些类来将 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+<; >c__DisplayClass0).variable

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

I wrote some classes to serialize System.Linq.Expressions to DataContracts to be able to send via WCF. It works quite good nice. the problem is when i want to serialize an expression that has a variable in it. here is an example to explain the problem:

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)

i am not having trouble to serialize the CASE 2 expression, but the the data i serialize is useless, since on the service side, there is nothing to resolve value(MyTest+<>c__DisplayClass0).variable

so i need to resolve the variables before i serialize that expression so that the CASE 2 expression serializes to same result as CASE1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恋竹姑娘 2024-12-27 13:33:18

对 VB 表示抱歉,但是 以下摘录是我在评论中提到的代码片段。我不认为它涵盖了所有基础(即它可能没有深入到足够深的地方,所以一定要测试它),但对于simple大多数例子来说它是有效的

:代码基于 此 MSDN Expression Visitor示例

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);
        }
    }
}   

希望这有帮助!

编辑: 我最初遇到的问题是我没有继续走当 MemberAccess 是非 TSource 类时,上述逻辑实际上应该递归地根除这些情况,因此请忽略我原来的评论。我已经在 Nullable 子句中留下了(在 else if 语句中,因为我没有这样做'不要认为现有的逻辑会涵盖这些情况,它也可能与泛型类发生冲突。

也就是说,这应该会给你带来好处。如果您不使用表达式访问者,您可以提供更多详细信息/代码吗?

祝你好运!

Sorry for the VB, but the following extract is the bit of code I meant in my comment. I don't think it covers all the bases (i.e. it may not be drilling down far enough so make sure you test it) but for simple most examples it works:

The code is based on 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);
        }
    }
}   

Hope this helps!

EDIT: The original issue I had was that I didn't continue walking the tree when the MemberAccess was a non TSource class, the above logic should actually recursively root those cases out so ignore my original comment. I've left in the Nullable<T> clause (on the else if) statement as I don't think the existing logic will cover those cases, it may also struggle with Generic classes.

That said, this should put you in good stead. If you're not using the Expression Visitor, can you provide some more details/code?

Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文