web-dev-qa-db-ja.com

表現木の活用

式ツリーは素晴らしい機能ですが、その実用的な用途は何ですか?それらは、ある種のコード生成やメタプログラミングなどに使用できますか?

66
Dmitri Nesteruk

Jonが指摘するように、私は.NET 3.5で generic operator を提供するためにそれらを使用しています。私はまた(MiscUtilで)それらを使用して、デフォルト以外のコンストラクターへの高速アクセスを提供します(コンストラクターでDelegate.CreateDelegateを使用することはできませんが、Expressionは正常に動作します)。

手動で作成された式ツリーの他の用途:

しかし、実際には、式は動的コードを書くための非常に用途の広い方法です。 Reflection.Emitよりもはるかに単純で、私のお金のために、CodeDOMよりも理解が簡単です。そして.NET 4.0では さらに多くのオプション が利用できます。 Expression私のブログ を使用してコードを記述する基本を示します。

41
Marc Gravell

Marc Gravellは MiscUtil でこれらを使用して generic operator を実装しています。

20
Jon Skeet

ExpressionTreeを使用してgeneric filter functionを作成したところです。皆さんとshareしたい...

Start

var allFiltered= Filter(AllCustomer, "Name", "Moumit");

public static List<T> Filter<T>(this List<T> Filterable, string PropertyName, object ParameterValue)
{
    ConstantExpression c = Expression.Constant(ParameterValue);
    ParameterExpression p = Expression.Parameter(typeof(T), "xx");
    MemberExpression m = Expression.PropertyOrField(p, PropertyName);
    var Lambda = Expression.Lambda<Func<T, Boolean>>(Expression.Equal(c, m), new[] { p });
    Func<T, Boolean> func = Lambda.Compile();
    return Filterable.Where(func).ToList();
}

One More

string singlePropertyName=GetPropertyName((Property.Customer p) => p.Name);

public static string GetPropertyName<T, U>(Expression<Func<T, U>> expression)
{
        MemberExpression body = expression.Body as MemberExpression;
        // if expression is not a member expression
        if (body == null)
        {
            UnaryExpression ubody = (UnaryExpression)expression.Body;
            body = ubody.Operand as MemberExpression;
        }
        return string.Join(".", body.ToString().Split('.').Skip(1));
}

Make it more expandable

string multiCommaSeparatedPropertyNames=GetMultiplePropertyName<Property.Customer>(c => c.CustomerId, c => c.AuthorizationStatus)

public static string GetMultiplePropertyName<T>(params Expression<Func<T, object>>[] expressions)
{
        string[] propertyNames = new string[expressions.Count()];
        for (int i = 0; i < propertyNames.Length; i++)
        {
            propertyNames[i] = GetPropertyName(expressions[i]);
        }

        return propertyNames.Join();
}

....... Reflectionを使用しても実行できることはわかっていますが、これは非常に高速であるか、最初のコンパイル後にLambdaと同等と言える...最初の反復は平均で10ミリ秒遅いだけです...これがExpression Treeマジックです。シンプルで素晴らしい....私は思う... !!!!!!!!

15
Moumit

それらを使用して、データの並べ替えやフィルタリングのためであっても、動的クエリを作成します。例として:

IQueryable<Data.Task> query = ctx.DataContext.Tasks;

if (criteria.ProjectId != Guid.Empty)
      query = query.Where(row => row.ProjectId == criteria.ProjectId);

if (criteria.Status != TaskStatus.NotSet)
      query = query.Where(row => row.Status == (int)criteria.Status);

if (criteria.DueDate.DateFrom != DateTime.MinValue)
      query = query.Where(row => row.DueDate >= criteria.DueDate.DateFrom);

if (criteria.DueDate.DateTo != DateTime.MaxValue)
     query = query.Where(row => row.DueDate <= criteria.DueDate.DateTo);

if (criteria.OpenDate.DateFrom != DateTime.MinValue)
     query = query.Where(row => row.OpenDate >= criteria.OpenDate.DateFrom);

var data = query.Select(row => TaskInfo.FetchTaskInfo(row));
12
mattruma

LINQプロバイダーの実装は、ほとんどが式ツリーを処理することによって行われます。また、コードからリテラル文字列を削除するためにも使用しています。

8

式ツリーを使用して数学式エバリュエーターを作成しました: C#の式ツリーを使用した式エバリュエーターの作成

6
Giorgi

これらを使用して、Google、Flickr、AmazonなどのWebサイト用の独自のlinqプロバイダー、独自のWebサイト、または別のデータプロバイダーを構築できます。

4
tuinstoel

元々 Jomo Fisher によって、 Gustavo Guerrastatic string dictionary の改訂版を公開しました。

式ツリーを介して、本当に(とんでもない)辞書を提供する動的な式。

実装は、入力文字列の長さに従って最初の文字、次に2番目の文字というように、現在の値を選択する動的決定木を作成します。

これは最終的に、同等のディクショナリよりもはるかに高速に実行されます。

2
damageboy