如何记录谓词表达式?

发布于 2024-10-20 04:29:11 字数 782 浏览 2 评论 0 原文

通常,我的存储库具有用于调试目的的日志记录语句,使我能够查看参数的值。最近,我沿着创建一个通用存储库的道路,该存储库将谓词表达式作为参数,以实现极大的灵活性,但是我无法找到一种将条件记录到远程有用的地方的体面方法。

示例方法:

public int GetCount<K>(Expression<Func<K, bool>> predicate) where K : class
{
    Logger.LogDebugMessage(String.Format("Parameters [predicate: {0}]", predicate == null ? string.Empty : predicate.Body.ToString()));

    ...
}

您可以看到我此时正在使用 Body.ToString(),但结果不太可读:

Parameters [predicate: (fa.SomeId == value(NameSpace.SomeClass+) >c__DisplayClass2).SomeId)]

最终我希望看到的是类似于以下内容的内容:

Parameters [predicate: (fa.SomeId == 1 && fa.Account.Name = = "MyName").SomeId)]

本质上,该日志的价值在于能够在发生故障时知道输入值。 有没有办法解决这个问题,强制 API 用户以字符串形式提供谓词?

Typically my repositories have logging statements for debugging purposes, allowing me to see values of parameters. Recently I went down the path of creating a generic repository that take predicate Expression as argument for great flexibility, however I cannot figure out a decent way of logging the condition to where it would be remotely useful.

Example Method:

public int GetCount<K>(Expression<Func<K, bool>> predicate) where K : class
{
    Logger.LogDebugMessage(String.Format("Parameters [predicate: {0}]", predicate == null ? string.Empty : predicate.Body.ToString()));

    ...
}

You can see I am using the Body.ToString() at this point, but the results are not-so-readble:

Parameters [predicate: (fa.SomeId == value(NameSpace.SomeClass+<>c__DisplayClass2).SomeId)]

Ultimately what I would love to see is something similar to the below:

Parameters [predicate: (fa.SomeId == 1 && fa.Account.Name == "MyName").SomeId)]

In essence the value of this log is being able to know the input values when something blows up.
Is there any way around this short of forcing the user of the API to supply the predicate as a string?

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

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

发布评论

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

评论(2

何时共饮酒 2024-10-27 04:29:11

Matt Warren 的这篇博客文章包含用变量名称替换局部变量引用的代码。因此,您将得到 predicate: (fa.SomeId == someValue),而不是 predicate: (fa.SomeId == value(NameSpace.SomeClass+<>c__DisplayClass2).SomeId)

博客文章:

http://blogs.msdn.com/b/mattwar/archive/2007/08/01/linq-building-an-iqueryable-provider-part-iii.aspx

来源:

public static class Evaluator
{
    /// <summary>
    /// Performs evaluation & replacement of independent sub-trees
    /// </summary>
    /// <param name="expression">The root of the expression tree.</param>
    /// <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param>
    /// <returns>A new tree with sub-trees evaluated and replaced.</returns>
    public static Expression PartialEval(Expression expression, Func<Expression, bool> fnCanBeEvaluated)
    {
        return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression);
    }

    /// <summary>
    /// Performs evaluation & replacement of independent sub-trees
    /// </summary>
    /// <param name="expression">The root of the expression tree.</param>
    /// <returns>A new tree with sub-trees evaluated and replaced.</returns>
    public static Expression PartialEval(Expression expression)
    {
        return PartialEval(expression, Evaluator.CanBeEvaluatedLocally);
    }

    private static bool CanBeEvaluatedLocally(Expression expression)
    {
        return expression.NodeType != ExpressionType.Parameter;
    }

    /// <summary>
    /// Evaluates & replaces sub-trees when first candidate is reached (top-down)
    /// </summary>
    class SubtreeEvaluator : ExpressionVisitor
    {
        HashSet<Expression> candidates;

        internal SubtreeEvaluator(HashSet<Expression> candidates)
        {
            this.candidates = candidates;
        }

        internal Expression Eval(Expression exp)
        {
            return this.Visit(exp);
        }

        protected override Expression Visit(Expression exp)
        {
            if (exp == null)
            {
                return null;
            }
            if (this.candidates.Contains(exp))
            {
                return this.Evaluate(exp);
            }
            return base.Visit(exp);
        }

        private Expression Evaluate(Expression e)
        {
            if (e.NodeType == ExpressionType.Constant)
            {
                return e;
            }
            LambdaExpression lambda = Expression.Lambda(e);
            Delegate fn = lambda.Compile();
            return Expression.Constant(fn.DynamicInvoke(null), e.Type);
        }
    }

    /// <summary>
    /// Performs bottom-up analysis to determine which nodes can possibly
    /// be part of an evaluated sub-tree.
    /// </summary>
    class Nominator : ExpressionVisitor
    {
        Func<Expression, bool> fnCanBeEvaluated;
        HashSet<Expression> candidates;
        bool cannotBeEvaluated;

        internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
        {
            this.fnCanBeEvaluated = fnCanBeEvaluated;
        }

        internal HashSet<Expression> Nominate(Expression expression)
        {
            this.candidates = new HashSet<Expression>();
            this.Visit(expression);
            return this.candidates;
        }

        protected override Expression Visit(Expression expression)
        {
            if (expression != null)
            {
                bool saveCannotBeEvaluated = this.cannotBeEvaluated;
                this.cannotBeEvaluated = false;
                base.Visit(expression);
                if (!this.cannotBeEvaluated)
                {
                    if (this.fnCanBeEvaluated(expression))
                    {
                        this.candidates.Add(expression);
                    }
                    else
                    {
                        this.cannotBeEvaluated = true;
                    }
                }
                this.cannotBeEvaluated |= saveCannotBeEvaluated;
            }
            return expression;
        }
    }
}

This blog post by Matt Warren contains code that replaces a local variable reference with the variable name. So, instead of predicate: (fa.SomeId == value(NameSpace.SomeClass+<>c__DisplayClass2).SomeId), you will get predicate: (fa.SomeId == someValue).

The blog post:

http://blogs.msdn.com/b/mattwar/archive/2007/08/01/linq-building-an-iqueryable-provider-part-iii.aspx

The source:

public static class Evaluator
{
    /// <summary>
    /// Performs evaluation & replacement of independent sub-trees
    /// </summary>
    /// <param name="expression">The root of the expression tree.</param>
    /// <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param>
    /// <returns>A new tree with sub-trees evaluated and replaced.</returns>
    public static Expression PartialEval(Expression expression, Func<Expression, bool> fnCanBeEvaluated)
    {
        return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression);
    }

    /// <summary>
    /// Performs evaluation & replacement of independent sub-trees
    /// </summary>
    /// <param name="expression">The root of the expression tree.</param>
    /// <returns>A new tree with sub-trees evaluated and replaced.</returns>
    public static Expression PartialEval(Expression expression)
    {
        return PartialEval(expression, Evaluator.CanBeEvaluatedLocally);
    }

    private static bool CanBeEvaluatedLocally(Expression expression)
    {
        return expression.NodeType != ExpressionType.Parameter;
    }

    /// <summary>
    /// Evaluates & replaces sub-trees when first candidate is reached (top-down)
    /// </summary>
    class SubtreeEvaluator : ExpressionVisitor
    {
        HashSet<Expression> candidates;

        internal SubtreeEvaluator(HashSet<Expression> candidates)
        {
            this.candidates = candidates;
        }

        internal Expression Eval(Expression exp)
        {
            return this.Visit(exp);
        }

        protected override Expression Visit(Expression exp)
        {
            if (exp == null)
            {
                return null;
            }
            if (this.candidates.Contains(exp))
            {
                return this.Evaluate(exp);
            }
            return base.Visit(exp);
        }

        private Expression Evaluate(Expression e)
        {
            if (e.NodeType == ExpressionType.Constant)
            {
                return e;
            }
            LambdaExpression lambda = Expression.Lambda(e);
            Delegate fn = lambda.Compile();
            return Expression.Constant(fn.DynamicInvoke(null), e.Type);
        }
    }

    /// <summary>
    /// Performs bottom-up analysis to determine which nodes can possibly
    /// be part of an evaluated sub-tree.
    /// </summary>
    class Nominator : ExpressionVisitor
    {
        Func<Expression, bool> fnCanBeEvaluated;
        HashSet<Expression> candidates;
        bool cannotBeEvaluated;

        internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
        {
            this.fnCanBeEvaluated = fnCanBeEvaluated;
        }

        internal HashSet<Expression> Nominate(Expression expression)
        {
            this.candidates = new HashSet<Expression>();
            this.Visit(expression);
            return this.candidates;
        }

        protected override Expression Visit(Expression expression)
        {
            if (expression != null)
            {
                bool saveCannotBeEvaluated = this.cannotBeEvaluated;
                this.cannotBeEvaluated = false;
                base.Visit(expression);
                if (!this.cannotBeEvaluated)
                {
                    if (this.fnCanBeEvaluated(expression))
                    {
                        this.candidates.Add(expression);
                    }
                    else
                    {
                        this.cannotBeEvaluated = true;
                    }
                }
                this.cannotBeEvaluated |= saveCannotBeEvaluated;
            }
            return expression;
        }
    }
}
夜灵血窟げ 2024-10-27 04:29:11

我曾经遇到过这个问题,并通过为所有可能被记录的谓词创建一个枚举来解决它,在我的例子中,这些谓词并不多。如果您的情况不是这样,只需为每个谓词创建一个枚举条目和一个 Dictionary, YourEnum>,并记录枚举的值而不是谓词。

I had this problem once, and solved it by creating an enum for all predicates that could possible be logged, which weren't that many in my case. If it isn't either in your case, just create one enum-entry per predicate and a Dictionary<Predicate<T>, YourEnum>, and log the value of the enum instead of the predicate.

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