5

現在、パラメーターとして を受け取るメソッドがFunc<Product, string>ありますが、それを にする必要がありますExpression<Func<Product, string>>。AdventureWorks を使用して、Func を使用してやりたいことの例を次に示します。

private static void DoSomethingWithFunc(Func<Product, string> myFunc)
{
    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(product => new
        {
            SubCategoryName = myFunc(product),
            ProductNumber = product.ProductNumber
        });
    }
}

次のようにしたいと思います。

private static void DoSomethingWithExpression(Expression<Func<Product, string>> myExpression)
{
    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(product => new
            {
                SubCategoryName = myExpression(product),
                ProductNumber = product.ProductNumber
            });
    }
}

ただし、私が直面している問題は、それmyExpression(product)が無効であることです (コンパイルされません)。他の投稿を読んだ後、その理由がわかりました。そして、キーの 2 番目の部分に変数が必要であるという事実がなければ、productおそらく次のように言うことができます。

var result = db.Products.GroupBy(myExpression);

しかしproduct、キーの 2 番目の部分 (ProductNumber) が必要なので、変数が必要です。だから私は今何をすべきか本当にわかりません。問題が発生するため、Func のままにしておくことはできません。product変数に渡す方法がわからないため、式の使用方法がわかりません。何か案は?

編集:メソッドを呼び出す方法の例を次に示します。

DoSomethingWithFunc(product => product.ProductSubcategory.Name);
4

2 に答える 2

4

Expression<T>オブジェクトとして表される式ツリーを、ラムダ式で表される「ツリーリテラル」の中央に接続する方法はありません。GroupBy手動で渡す式ツリーを作成する必要があります。

// Need an explicitly named type to reference in typeof()
private class ResultType
{
     public string SubcategoryName { get; set; }
     public int ProductNumber { get; set; }|
}

private static void DoSomethingWithExpression(
    Expression<Func<Product,
    string>> myExpression)
{
    var productParam = Expression.Parameter(typeof(Product), "product");
    var groupExpr = (Expression<Func<Product, ResultType>>)Expression.Lambda(
        Expression.MemberInit(
           Expression.New(typeof(ResultType)),
           Expression.Bind(
               typeof(ResultType).GetProperty("SubcategoryName"),
               Expression.Invoke(myExpression, productParam)),
           Expression.Bind(
               typeof(ResultType).GetProperty("ProductNumber"),
               Expression.Property(productParam, "ProductNumber"))),
        productParam);
    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(groupExpr);
    }
}
于 2009-10-20T17:21:49.217 に答える
3

よく考えてみると、式のコンパイルは機能しません。

GroupBy 式を手動で作成する必要があります。つまり、匿名型は使用できません。式の残りの部分を作成してから逆コンパイルして、生成された式ツリーを確認することをお勧めします。最終結果はmyExpression、必要に応じて の一部を使用すると、次のようになります。

private static void DoSomethingWithExpression(Expression<Func<Product, string>> myExpression)
{
    var productParam = myExpression.Parameters[0];

    ConstructorInfo constructor = ...; // Get c'tor for return type

    var keySelector = Expression.Lambda(
                          Expression.New(constructor,
                              new Expression[] {
                                  productParam.Body,
                                  ... // Expressions to init other members
                              },
                              new MethodInfo[] { ... }), // Setters for your members
                          new [] { productParam });

    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(keySelector);

        // ...
    }
}
于 2009-10-20T17:06:03.897 に答える