2009-10-21 4 views
4

J'ai essayé de simplifier cet exemple, car le code dans lequel je joue est plus complexe. Donc, alors que cet exemple peut sembler stupide, supporter avec moi. Disons que je travaille avec la base de données AdventureWorks et je décide que je veux ajouter une propriété appelée Blarg à la table Product qui retourne une expression qui contient le code que je voudrais utiliser en plusieurs endroits:Récupération d'une expression à partir d'une propriété et ajout à une arborescence d'expressions

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

Ce que je vouloir faire est de créer un arbre d'expression d'expression, l'obtenir l'expression de Product.Blarg, et le groupe par le résultat. Quelque chose comme ceci:

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]]'." 
} 

Il est évident que groupExpression est incorrect (voir le commentaire de code pour l'exception), mais je ne sais pas comment je devrais faire cela. Ce que je pensais que je disais est "obtenir l'expression à partir du product.Blarg, l'exécuter, et retourner le résultat de la chaîne." Je suppose que ce n'est pas ce que je dis réellement là, cependant. J'essaie toujours de comprendre les arbres d'expression. Une idée de comment je pourrais retirer ça?

Répondre

3

Lorsque vous appelez Expression.Invoke, le premier argument doit être un LambdaExpression existant - il ne peut pas être un Expressionà un LambdaExpression. Ou en d'autres termes: il n'évaluera pas Product.Blargpar ligne et utilisera une sous-expression différente à chaque fois.

Au lieu de cela, vous récupérerez cette lambda d'abord, ce qui peut-être static et l'accès via la réflexion si vous ne connaissez que par son nom:

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

Et passer lambda en tant que l'argument Expression.Invoke; voici un LINQ à des objets de travail pleinement exemple montrant ce (via 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(); 
    } 
} 
+0

Quelque chose semble louche avec cet exemple de code (sauf si LambdaExpression a un mécanisme de distribution drôle). – leppie

+0

Ca marche, chou! Je ne pensais pas :) – leppie

+0

@marc: quelle est la raison pour laquelle vous allez ce long chemin, quand ma solution ci-dessus est suffisante? – leppie

3
var qry = data.AsQueryable().GroupBy(Blarg).ToList(); 

Cela fonctionne, même que le code de Marc.

Remarque: Blarg est déjà correct, il n'y a aucune raison de le «ré-invoquer».

+1

Vous avez raison ;-p Je pensais au cas plus général, où vous voulez faire d'autres vaudou avec «l'expression». Si vous êtes déjà en train de jouer dans ce domaine, il y a de fortes chances que vous vouliez faire quelque chose de génial. –

Questions connexes