Comment créer Expression LINQ Arborescence pour sélectionner un type anonyme
Je voudrais générer l'instruction select suivante dynamiquement à l'aide de l'expression des arbres:
var v = from c in Countries
where c.City == "London"
select new {c.Name, c.Population};
J'ai travaillé sur la façon de générer
var v = from c in Countries
where c.City == "London"
select new {c.Name};
mais je n'arrive pas à trouver un constructeur/surcharge qui va me permettre de spécifier plusieurs propriétés dans mon sélectionnez lambda.
- Pourriez-vous poster le code que vous venez de si loin?
Vous devez vous connecter pour publier un commentaire.
Cela peut être fait, comme mentionné, avec l'aide de la Réflexion Émettent et une classe d'aide, j'ai inclus ci-dessous. Le code ci-dessous est un travail en cours, donc le prendre pour ce qu'il vaut... 'il fonctionne sur ma boîte". Le SelectDynamic méthode de la classe doit être jeté dans une statique de la classe de méthode d'extension.
Comme prévu, vous n'aurez pas de Intellisense car le type n'est pas créé jusqu'à ce que l'exécution. Les bonnes œuvres de retard lié à des contrôles de données.
Unable to create a constant value of type
erreur. J'ai fixé ce, en remplacement deExpression.Constant(source)
avecsource.Expression
sur la dernière ligne. Espérons que cela aide quelqu'un 🙂.GetProperties()
sur le nouveau type renvoie un tableau vide. Pour obtenir celles-ci, est nécessaire pour aller avec la plus complexe, la solution à cette question? stackoverflow.com/a/3862241/701346Accepté la réponse est très utile, mais j'avais besoin de quelque chose d'un peu plus près à un réel de type anonyme.
Un réel anonyme de type a des propriétés en lecture seule, un constructeur pour remplir toutes les valeurs, une mise en œuvre d'égal à Égal/GetHashCode de comparer les valeurs de chaque propriété, et une mise en œuvre ToString qui inclut le nom/valeur de chaque propriété. (Voir https://msdn.microsoft.com/en-us/library/bb397696.aspx pour une description complète des types anonymes.)
Basé sur la définition de classes anonymes, j'ai mis une classe qui génère des dynamiques des types anonymes sur github à https://github.com/dotlattice/LatticeUtils/blob/master/LatticeUtils/AnonymousTypeUtils.cs. Le projet contient également certains des tests unitaires pour s'assurer du faux types anonymes se comportent comme des vrais.
Voici un exemple très simple d'utilisation:
Aussi, une autre remarque: j'ai constaté que lors de l'utilisation d'une dynamique de type anonyme avec Entity Framework, le constructeur doit être appelé avec les "membres" jeu de paramètres. Par exemple:
Si vous avez utilisé l'une des versions de l'Expression.Les nouveaux qui ne comprennent pas les "membres" de paramètre, Entity Framework ne serait pas le reconnaître comme le constructeur d'un type anonyme. Donc je suppose que signifie un réel anonyme de type du constructeur d'expression que les "membres" de l'information.
Vous pouvez utiliser le IQueryable-Extensions ici, qui est une mise à la solution décrite par la "Ethan J. Brown":
https://github.com/thiscode/DynamicSelectExtensions
L'Extension construit dynamiquement un type anonyme.
Ensuite, vous pouvez faire ceci:
Peut-être un peu en retard, mais il peut aider à quelqu'un.
Vous Pouvez générer des dynamiques de sélection par appel
DynamicSelectGenerator
de sélectionner à partir d'une entité.Et de l'utilisation par le présent code:
Je ne crois pas que vous serez en mesure d'atteindre cet objectif. Bien que quand vous ne
select new { c.Name, c.Population }
il semble que vous n'êtes pas la création d'une classe vous êtes réellement. Si vous avez un coup d'oeil à la sortie compilée dans le Réflecteur ou cru, IL vous serez en mesure de voir ça.Vous aurez une classe qui ressemblerait à quelque chose comme ceci:
(Ok, j'ai nettoyé une touche, depuis un bien est vraiment juste une
get_Name()
etset_Name(name)
méthode de jeu de toute façon)Ce que vous essayez de faire est la bonne dynamique de la création de classes, quelque chose qui ne sera pas disponible jusqu'à ce que .NET 4.0 vient de sortir (et même alors, je ne suis pas vraiment sûr si ça va être en mesure de réaliser ce que vous voulez).
Vous êtes la meilleure solution serait de définir les différents anonyme classes et ensuite avoir une sorte de logique de contrôle afin de déterminer celui qui à créer, et à le créer, vous pouvez utiliser l'objet
System.Linq.Expressions.NewExpression
.Mais, il se peut (en théorie au moins) possible de le faire, si vous vous sentez vraiment hard-core sur le sous-jacent LINQ fournisseur. Si vous sont de la rédaction de votre propre fournisseur LINQ vous pouvez détecter si actuellement analysé l'expression est de Sélectionner, puis de déterminer le
CompilerGenerated
classe, réfléchir pour son constructeur et de créer.Défi n'est pas une tâche simple, mais il serait comment LINQ to SQL, LINQ to XML, etc tous le faire.
Vous pouvez utiliser un paramètre de classe au lieu de travailler avec un type anonyme. Dans votre exemple, vous pouvez créer un paramètre de la classe comme ceci:
...et le mettre dans votre sélectionner comme ceci:
Ce que vous obtenez est quelque chose du type
IQueryable<ParamClass>
.Cette compile, je sais pas si il fonctionne cependant...
En supposant que p est ce que votre transformation, et l'instruction select retourne un anon type, à l'aide de la déclaration de la fonction de lambda.
Edit: aussi, je ne sais pas comment vous permettrait de générer dynamiquement. Mais au moins, il vous montre comment utiliser la sélection lambda de retour d'un anon type avec plusieurs valeurs
Edit2:
Vous devriez également garder à l'esprit, que le compilateur c# génère les classes statiques de la anon type. Si l'anon type n'ont en fait un type après le moment de la compilation. Donc, si votre production de ces requêtes au moment de l'exécution (qui je suppose que vous êtes), vous pourriez être la construction d'un type à l'aide de diverses méthodes de réflexion (je crois que vous pouvez les utiliser pour faire des types à la volée) charge de la création de types dans le contexte d'exécution et les utiliser dans la sortie générée.
Je pense que la plupart des choses sont déjà répondu - comme Slace dit, vous avez besoin d'un peu de classe qui serait retourné à partir de la
Select
méthode. Une fois que vous avez la classe, vous pouvez utiliser leSystem.Linq.Expressions.NewExpression
méthode pour créer l'expression.Si vous voulez vraiment pour ce faire, vous pouvez générer de la classe au moment de l'exécution trop. C'est un peu plus de travail, car il ne peut pas être fait à l'aide de LINQ des arbres d'Expression, mais c'est possible. Vous pouvez utiliser
System.Reflection.Emit
espace de noms pour ce faire, j'ai juste fait une recherche rapide et voici un article qui explique cela:Vous pouvez utiliser l'Expression Dynamique de l'API qui permet de créer dynamiquement des select, comme ceci:
Vous avez besoin de la Dynamique.cs fichier à partir du LINQ et de la langue des échantillons pour Visual Studio pour que cela fonctionne, les deux sont liées au bas de cette page. Vous pouvez également voir un exemple montrant en action, à la même URL.