4

実際のコードはもっと複雑なので、この例を単純化しようとしました。この例はばかげているように見えるかもしれませんが、ご容赦ください。たとえば、AdventureWorks データベースを操作していて、いくつかの場所で使用したいコードを含む式を返すテーブルに呼び出さBlargれるプロパティを追加することにしました。Product

public partial class Product
{
    public Expression<Func<Product, string>> Blarg
    {
        get { return product => product.ProductModelID.HasValue ? "Blarg?" : "Blarg!"; }
    }
}

私がやりたいのは、式の式ツリーを作成し、Product.Blarg から Expression を取得し、結果によってグループ化することです。このようなもの:

var productParameter = Expression.Parameter(typeof(Product), "product");

// The Problem
var groupExpression = Expression.Lambda<Func<Product, string>>(
    Expression.Invoke(
        Expression.Property(productParameter, "Blarg"), 
        productParameter), 
    productParameter);

using (AdventureWorksDataContext db = new AdventureWorksDataContext())
{
    var result = db.Products.GroupBy(groupExpression).ToList();
    // Throws ArgumentException: "The argument 'value' was the wrong type. 
    //  Expected 'System.Delegate'. 
    //  Actual 'System.Linq.Expressions.Expression`1[System.Func`2[LINQ_Test.Product,System.String]]'."
}

明らかgroupExpressionに間違っています (例外についてはコードのコメントを参照してください) が、どうすればよいかわかりません。私が言っていると思ったのは、「 から Expression を取得し、product.Blargそれを実行して、文字列の結果を返す」ということです。でも、それは私が実際に言っていることではないと思います。私はまだ式ツリーを理解しようとしています。どうすればこれをやってのけることができますか?

4

2 に答える 2

3

を呼び出すExpression.Invoke場合、最初の引数は既存のものでなければなりません。を にするLambdaExpressionことはできません。つまり、行ごとに評価 して、毎回異なる部分式を使用するわけではありません。Expression LambdaExpressionProduct.Blarg

代わりに、最初にこのラムダを取得します。名前だけを知っている場合は、おそらくそれstaticを作成し、リフレクションを介してアクセスします。

var lambda = (LambdaExpression) typeof(Product)
          .GetProperty("Blarg").GetValue(null,null);

lambdaそして引数としてExpression.Invoke;に渡します。これを示す完全に機能する LINQ-to-Objects の例を次に示します (経由AsQueryable()):

using System;
using System.Linq;
using System.Linq.Expressions;
public partial class Product
{
    public static Expression<Func<Product, string>> Blarg
    {
        get { return product => product.ProductModelID.HasValue ? "Blarg?" : "Blarg!"; }
    }
    public int? ProductModelID { get; set; }

    static void Main()
    {
        var lambda = (LambdaExpression)typeof(Product)
          .GetProperty("Blarg").GetValue(null, null);

        var productParameter = Expression.Parameter(typeof(Product), "product");

        // The Problem
        var groupExpression = Expression.Lambda<Func<Product, string>>(
            Expression.Invoke(
                lambda,
                productParameter),
            productParameter);

        var data = new[] {
            new Product { ProductModelID = 123},
            new Product { ProductModelID = null},
            new Product { ProductModelID = 456},
        };
        var qry = data.AsQueryable().GroupBy(groupExpression).ToList();
    }
}
于 2009-10-21T11:37:46.387 に答える
3
var qry = data.AsQueryable().GroupBy(Blarg).ToList();

マークのコードと同じように機能します。

注:Blargは既に正しいので、「再起動」する理由はありません。

于 2009-10-21T11:50:52.953 に答える