4

これが私のインターフェイスと列挙型で、少し馬鹿げています。:

public interface IExpression
{
    ExpressionType ExpressionType { get; }
}

public interface ILiteralExpression : IExpression
{
    object Value { get; set; }
}

public interface IOperatorExpression : IExpression
{
    IExpression[] Operands { get; set; }

    string OperatorUniqueName { get; set; }

    IOperatorExpression SetOperand(int index, IExpression expression);
}

public enum ExpressionType
{
    Operator,
    Literal
}

式を作成するには、次のようにします。

var expression = ExpressionManager.Engines["Default"].Parser.Parse("1 + 3 * 4 + \"myVariable\"");

これは次のようなものと同等です:

var expression1 = ExpressionManager.CreateOperator("Add", 2).
    SetOperand(0, ExpressionManager.CreateOperator("Add", 2).
        SetOperand(0, ExpressionManager.CreateLiteral(1)).
        SetOperand(1, ExpressionManager.CreateOperator("Multiply", 2).
            SetOperand(0, ExpressionManager.CreateLiteral(3)).
            SetOperand(1, ExpressionManager.CreateLiteral(4)))).
    SetOperand(1, ExpressionManager.CreateLiteral("myVariable"));

私はこのようなことを(効率的に)できるようにしたいと思います:

(from e in expression
 where e is ILiteralExpression && "myVariable".Equals(((ILiteralExpression)e).Value)
 select (ILiteralExpression)e).ToList().
 ForEach(e => e.Value = 2);

の実装などを行う必要があると思いますがIQueryable、どこから始めればよいかわかりません。助言がありますか?

4

2 に答える 2

3

クラスSystem.Linq.Expressionsのファクトリ メソッドを使用して、式ツリーをたどり、各要素を名前空間からオブジェクトに変換します。Expression

クラスを変更して、ビジター パターンIExpressionを実装できるメソッドを追加できない場合は、古いスタイルの型チェックに頼ることができます。

private static Expression ConvertExpression(IExpression expr) {
    if (expr is ILiteralExpression) {
        return Expression.Constant(((ILiteralExpression)expr).Value);
    }
    if (expr is IOperatorExpression) {
        var ops = ((IOperatorExpression)expr)
            .Operands
            .Select(ConvertExpression)
            .ToList();
        var res = ops[0];
        for (int i = 1 ; i != ops.Length ; i++) {
            if (((IOperatorExpression)expr).OperatorUniqueName == "+") {
                res = Expressions.Add(res, ops[i]);
            } else if (((IOperatorExpression)expr).OperatorUniqueName == "-") {
                res = Expressions.Subtract(res, ops[i]);
            } else if (...) {
            }
        }
        return res;
    }
}

もちろん、このメソッドにはさらに多くのロジックが必要になります。重要な部分はパラメーターを渡すことです。変数がどこにあり、その型が何であるかを把握し、それを使用Expression.ParameterExpressionして作成し、メソッドを使用して変換された式をFunc<...>何らかの種類にコンパイルする必要がありますLambdaExpression.Compile。コンパイル済みのラムダを使用すると、式を LINQ のインメモリ フレームワークにプラグインできます。

訪問可能にできる場合はIExpressions、式をウォークスルーし、スタックを使用して LINQ 式に変換する訪問者を追加します。

于 2012-07-23T14:01:25.870 に答える
1

あなたが探しているのは、独自のLINQクエリプロバイダーを構築することです。許可するLINQ操作(WHERE、OrderByなど)を選択できます

これは、私が1つ書いたときに最も役立ったブログ投稿シリーズです:http: //blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part- i.aspx

于 2012-07-23T13:50:55.733 に答える