4

.NET 3.5 でビルドされたプロジェクトで、LINQ 式を使用して実行時にコードを動的に生成しています。LINQ 式は Compile メソッドを使用してコンパイルされ、後で LINQ to オブジェクトの述語として使用するために格納されます。

式は非常に複雑で、デバッグが難しい場合があります。

以下は、Visual Studio のデバッガー ビジュアライザーで表示される式の例です。

{request => (Invoke(workEnvelopeHead => (workEnvelopeHead.Method = value(Wombl.Scenarios.CannedResponses+<>c_ DisplayClass58).pipeline), request.WorkEnvelope.Head) And Invoke(body => Invoke(value(Wombl.Scenarios) .CannedResponses+<>c _DisplayClass78).isMatch, body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}

上記のような式を最適化して、value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipeline式が変数の値である定数に置き換えられるようにしたいと考えています。

この特定のケースでvalue(Wombl.Scenarios.CannedResponses+<>c__DisplayClass58).pipelineは、親スコープ内の変数へのラムダ内の参照です。何かのようなもの:

var pipeline = "[My variable's value here]";
// My lambda expression here, which references pipeline
// Func<RequestType, bool> predicate = request => ........ workEnvelopeHead.Method == pipeline ..........

最適化された元の式は次のようになります。

{request => (Invoke(workEnvelopeHead => (workEnvelopeHead.Method = "[My variable's value here]", request.WorkEnvelope.Head) And Invoke(body => > Invoke(value(Wombl.Scenarios.CannedResponses+<>c__DisplayClass78)) .isMatch, body.SingleOrDefault()),Convert(request.WorkEnvelope.Body.Any)))}

コンパイルする前に、実行時に LINQ 式に対してそのような最適化を行うにはどうすればよいですか?

4

1 に答える 1

1

そこで、先に進んで、変数参照を実際の値に置き換える式ビジターを作成しました。結局、そうするのはそれほど難しくありませんでした。

使用法:

var simplifiedExpression = ExpressionOptimizer.Simplify(complexExpression);

クラス:

.NET 3.0では内部であるため、このページのコードサンプルから取得したExpressionVisitorを継承しています。.NET 4.0では、クラスはパブリックですが、このクラスにいくつかの変更が必要になる場合があります。

public sealed class ExpressionOptimizer : ExpressionVisitor
{
    private ExpressionOptimizer()
    {
    }

    #region Methods

    public static Expression<TDelegate> Simplify<TDelegate>(Expression<TDelegate> expression)
    {
        return expression == null
                   ? null
                   : (Expression<TDelegate>) new ExpressionOptimizer().Visit(expression);
    }

    private static bool IsPrimitive(Type type)
    {
        return type.IsPrimitive
               || type.IsEnum
               || type == typeof (string)
               || type == typeof (DateTime)
               || type == typeof (TimeSpan)
               || type == typeof (DateTimeOffset)
               || type == typeof (Decimal)
               || typeof(Delegate).IsAssignableFrom(type);
    }

    protected override Expression VisitMemberAccess(MemberExpression memberExpression)
    {
        var constantExpression = memberExpression.Expression as ConstantExpression;

        if (constantExpression == null || !IsPrimitive(memberExpression.Type))
            return base.VisitMemberAccess(memberExpression);

        // Replace the MemberExpression with a ConstantExpression
        var constantValue = constantExpression.Value;
        var propertyInfo = memberExpression.Member as PropertyInfo;
        var value = propertyInfo == null
                        ? ((FieldInfo) memberExpression.Member).GetValue(constantValue)
                        : propertyInfo.GetValue(constantValue, null);

        return Expression.Constant(value);
    }

    #endregion
}
于 2011-05-18T14:52:12.237 に答える