Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将表达式编译到实际结果?_C#_C# 4.0_Expression Trees - Fatal编程技术网

C# 如何将表达式编译到实际结果?

C# 如何将表达式编译到实际结果?,c#,c#-4.0,expression-trees,C#,C# 4.0,Expression Trees,我正在围绕web服务调用构建一个API,使用表达式允许开发人员指定查询,并让ExpressionVisitor将表达式转换为查询字符串。该请求是包含查询字符串的特定元素的XML 例如,我可以这样做,检索银行名称为bank 1或bank 2的所有支票账户: “bankname='银行1'或bankname='银行2'” web服务可以处理复杂得多的查询,但我现在就坚持使用它 所以我有一个类检查帐户: [IntacctObject("checkingaccount")] public class

我正在围绕web服务调用构建一个API,使用表达式允许开发人员指定查询,并让ExpressionVisitor将表达式转换为查询字符串。该请求是包含查询字符串的特定元素的XML

例如,我可以这样做,检索银行名称为bank 1或bank 2的所有支票账户:

“bankname='银行1'或bankname='银行2'”

web服务可以处理复杂得多的查询,但我现在就坚持使用它

所以我有一个类检查帐户:


[IntacctObject("checkingaccount")]
public class CheckingAccount : Entity
{
    [IntacctElement("bankaccountid")]
    public string Id { get; set; }

    [IntacctElement("bankname")]
    public string BankName { get; set; }
}
以及ExpressionVisitor,其主要功能是转换如下表达式:

Expression> expression = ca => ca.BankName == "Bank 1" || ca.BankName == "Bank 2" 我知道如何处理一个简单的局部变量(即string bankName=“Bank 2”),但处理另一种类型的变量(var account=new CheckingAccount{bankName=“Bank 1”)要复杂得多

归根结底,这些都是我现在需要解决的重大问题。我知道还有更复杂的情况,但我现在不太关心这些

这是我的表达式访问者(请注意方法CreateFilter上的通用约束):

如果你想了解更多细节,请告诉我


谢谢

如果您有兴趣使用开源第三方库为您完成这项工作,您可以签出。我相信它能满足您的需求。

看一看。他提供了一个类的源代码,并解释了它是如何做到这一点的。它也包含在中。

您的过滤器是否总是要为二进制op左侧的Entity.Property?它们将是属性或字段。我看到您接受了我对您的另一个问题的回答,我的回答是否足够清晰,您可以将QueryFilter类集成到中?我在发布此问题后才真正看到这一点。它似乎确实起作用了。但奇怪的是,我最初所做的(不是在问题中公布的)不起作用。起初,我尝试了一些非常类似的东西:Expression.Lambda(constantExpressionNode,typeof(object)).Compile().Invoke()。之所以不起作用,是因为constantExpressionNode并不总是一个返回“object”类型的表达式。类型将与字段成员相同,可以是string/int/datetime等。这就是为什么我使用了泛型“Expression.Lambda”和泛型delegates,因为序列化程序将如何将任何LINQ表达式转换为XElement,然后可以通过连接将其转换为xml字符串,这似乎正是op想要做的。如果您能指出所缺少的内容,我将不胜感激。在我阅读问题的方式中,他希望将表达式转换为非常特定的形式(示例是
“bankname='Bank 1'或bankname='Bank 2'”
),而不是一些XML。“请求是包含查询字符串的特定元素的XML。”在我看来,他似乎试图将查询转换为序列化的xml字符串,而我所指的库就是这样做的。由于它进行序列化和反序列化,并且表达式有一个.ToString()方法使其更为纯文本,因此这是我所能想到的最接近的方法。

var account = new CheckingAccount { BankName = "Bank 1" };
string bankName = "Bank 2";

Expression> expression = ca => ca.BankName == account.BankName || ca.BankName == bankName;

internal class IntacctWebService30ExpressionVisitor : ExpressionVisitor
{
    private readonly List _Filters = new List();
    private IntacctWebServicev30SimpleQueryFilter _CurrentSimpleFilter;
    private IntacctWebServicev30ComplexQueryFilter _CurrentComplexFilter;
    private MemberExpression _CurrentMemberExpression;

    public string CreateFilter(Expression> expression) where TEntity : Entity
    {

        Visit(expression);

        string filter = string.Join(string.Empty, _Filters.Select(f => f.ToString()).ToArray());
        return filter;
    }

    protected override Expression VisitBinary(BinaryExpression node)
    {
        switch (node.NodeType)
        {
            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
                _CurrentComplexFilter = new IntacctWebServicev30ComplexQueryFilter { ExpressionType = node.NodeType };
                break;
            case ExpressionType.Equal:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.NotEqual:
                _CurrentSimpleFilter = new IntacctWebServicev30SimpleQueryFilter { ExpressionType = node.NodeType };
                break;
        }

        return base.VisitBinary(node);
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        var attr = node.Member.GetAttribute();
        if (attr != null)
            _CurrentSimpleFilter.FieldName = attr.FieldName;
        else
            _CurrentMemberExpression = node;

        return base.VisitMember(node);
    }

    protected override Expression VisitConstant(ConstantExpression node)
    {
        object value = Expression.Lambda>(node).Compile().Invoke();

        string fieldValue = extraxtFieldValue(value, node);

        _CurrentSimpleFilter.FieldValue = fieldValue;

        if (_CurrentComplexFilter != null)
        {
            if (_CurrentComplexFilter.Left == null)
            {
                _CurrentComplexFilter.Left = _CurrentSimpleFilter;
            }
            else if (_CurrentComplexFilter.Right == null)
            {
                _CurrentComplexFilter.Right = _CurrentSimpleFilter;
                _Filters.Add(_CurrentComplexFilter);
            }
            else
                throw new InvalidOperationException();
        }
        else
        {
            _Filters.Add(_CurrentSimpleFilter);
        }

        return base.VisitConstant(node);
    }

    private string extraxtFieldValue(object value)
    {
        string fieldValue;
        if (value is DateTime)
            fieldValue = ((DateTime)value).ToString("yyyy-MM-dd");
        else if (value is string)
            fieldValue = value.ToString();
        else if (value.GetType().IsEnum)
        {
            throw new NotImplementedException();
        }
        else
        {
            // Not sure if this is the best way to do this or not but can't figure out how
            // else to get a variable value.

            // If we are here then we are dealing with a property, field, or variable.
            // This means we must extract the value from the object.
            // In order to do this we will rely on _CurrentMemberExpression
            if (_CurrentMemberExpression.Member.MemberType == MemberTypes.Property)
            {
                fieldValue = value.GetType().GetProperty(_CurrentMemberExpression.Member.Name).GetValue(value, null).ToString();
            }
            else if (_CurrentMemberExpression.Member.MemberType == MemberTypes.Field)
            {
                fieldValue = value.GetType().GetFields().First().GetValue(value).ToString();
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        return fieldValue;
    }
}