Comment instancier et initialiser un objet dynamique dans l'arborescence des expressions?

.net c# dynamic expression-trees iqueryable

Question

Lorsque vous travaillez avec IQuerayble<TItem> vous pouvez appeler Select comme IQuerayble<TItem> :

query.Select( item => new { A=item.Prop1, B=item.Prop2});

Et la méthode Select attend Expression<Func<TItem,TResult>>

J'ai besoin d'utiliser ExpandoObject au lieu de la classe anonyme mais typée statiquement.

Si c'était possible, cela ressemblerait à:

query.Select( item => dynamic new ExpandoBoject { A=item.Prop1, B=item.Prop2});

Je veux donc construire l'arbre d' Expression<Func<TItem,ExpandoObject>> où les propriétés de l'objet sont initialisées de la même manière qu'avec le type anonyme.
La fonctionnalité dynamique n’est nécessaire que pour l’initialisation; il est donc ExpandoObject que Func renvoie ExpandoObject au lieu de dynamic .

Je ne trouve pas beaucoup de documentation sur Expression.Dynamic et les classeurs correspondants à utiliser.


Mise à jour 1

Pourquoi ai-je besoin de tout ça?
Parce que je veux obtenir des clés primaires .
Je veux le faire pour n'importe quel type d'entité.

Je sais comment obtenir la liste des propriétés composant PK, mais je dois maintenant faire une projection délicate de l'entité vers EntityKey . Eh bien, peut être au même équivalent de cette classe.

var keys = context.Set<TEntity>().Where(Expression<Func<TEntity,bool>).Select(Expression<Func<TEntity,EntityKey>>);

Comme je l'ai noté dans les commentaires, les lambdas contenant des blocs ne peuvent pas être convertis en arbres d'expression, je ne peux donc pas simplement créer le dictionnaire et le remplir. Maintenant, je joue avec l'arbre d'expression sémantiquement proche de ce code:

var dict = new Dictionary<string,object>();
dict.Add("Prop1",value1);
dict.Add("Prop2",value2);
return dict

Mais je doute que EF puisse analyser l'expression contenant des blocs. Besoin de vérifier.
Et je suis curieux de savoir si cela fonctionnera avec des objets dynamiques et Expression.MemberInit, car cela fonctionne avec des objets statiques.


Mise à jour 2

Entity Framework ne prend pas en charge la syntaxe d'initialisation de dictionnaire.
Il lève une NotSupportedException avec le message suivant: Seuls les éléments d'initialiseur de liste comportant un seul élément sont pris en charge dans LINQ to Entities.


Mise à jour 3

EF ne prend pas non plus en charge les expressions de bloc.
NotSupportedException avec message: Expression LINQ inconnue de type 'Block'.

Réponse populaire

Maintenant, je joue avec l'arbre d'expression sémantiquement proche de ce code:

var dict = new Dictionary<string,object>();
dict.Add("Prop1",value1);
dict.Add("Prop2",value2);
return dict;

Vous pouvez le faire, car vous pouvez écrire ce code sous la forme d'une expression unique comme celle-ci:

new Dictionary<string, object>
{
    { "Prop1", value1 },
    { "Prop2", value2 }
};

Et vous pouvez créer un arbre d’expression contenant cette expression (qu’EF devrait pouvoir gérer) comme ceci:

var addMethod = typeof(Dictionary<string, object>).GetMethod("Add");

var expression = Expression.Lambda<Func<Dictionary<string, object>>>(
    Expression.ListInit(
        Expression.New(typeof(Dictionary<string, object>)),
        Expression.ElementInit(
            addMethod,
            Expression.Constant("Prop1"),
            value1Expression),
        Expression.ElementInit(
            addMethod,
            Expression.Constant("Prop2"),
            value2Expression)),
    itemParameterExpression);


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi