9

通常、私のリポジトリにはデバッグ目的のロギングステートメントがあり、パラメータの値を確認できます。最近、柔軟性を高めるために述語式を引数として取る汎用リポジトリを作成する道を歩みましたが、リモートで役立つ場所に条件を記録する適切な方法を理解できません。

方法の例:

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のユーザーに述語を文字列として提供するように強制するこの不足を回避する方法はありますか?

4

2 に答える 2

6

Matt Warrenによるこのブログ投稿には、ローカル変数参照を変数名に置き換えるコードが含まれています。したがって、の代わりにpredicate: (fa.SomeId == value(NameSpace.SomeClass+<>c__DisplayClass2).SomeId)、を取得しpredicate: (fa.SomeId == someValue)ます。

ブログ投稿:

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;
        }
    }
}
于 2011-03-03T18:21:51.507 に答える
0

私は一度この問題を抱えていましたが、ログに記録される可能性のあるすべての述語の列挙型を作成することで解決しましたが、私の場合はそれほど多くはありませんでした。どちらでもない場合は、述語ごとに1つの列挙型エントリとを作成しDictionary<Predicate<T>, YourEnum>、述語の代わりに列挙型の値をログに記録します。

于 2011-03-03T17:58:20.730 に答える