Membre dynamique expression

c# dynamic expression-trees linq

Question

Je veux créer un MemberExpression ne connaissant que le nom du champ; par exemple:

public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>(string fieldName)
    {
        PropertyInfo fieldPropertyInfo;

        fieldPropertyInfo = typeof(TModel).GetProperty(fieldName);

        var entityParam = Expression.Parameter(typeof(TModel), "e"); // {e}
        var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
        var lambda = Expression.Lambda(columnExpr, entityParam) as Expression<Func<TModel, T>>; // {e => e.column}

        return lambda;
    }

Le problème avec ce qui précède est que le type de champ doit être fortement typé. Passer "objet" en tant que type de champ ne fonctionne pas. Est-il possible de générer cela? Même le LINQ dynamique ne semble pas fonctionner.

Réponse acceptée

Votre code pose plusieurs problèmes:

  1. Le paramètre de votre méthode s'appelle fieldName , mais vous en sortez une propriété .
  2. Vous utilisez la méthode Expression.Lambda non générique pour générer l'expression, qui peut choisir un type de délégué inapproprié si l'argument de type T transmis à la méthode n'est pas identique au type de propriété. Dans ce cas, la conversion d' as de l'expression vers le type de retour de la méthode échouera et sera évaluée à null . Solution: utilisez la méthode Lambda générique avec les arguments de type appropriés. Aucun casting requis.
  3. Si vous résolvez le deuxième problème, les choses fonctionneront correctement si une conversion de référence sûre est disponible du type de propriété vers T , mais pas lorsque des conversions plus complexes telles que la boxe / levage sont requises. Solution: utilisez la méthode Expression.Convert si nécessaire.

Voici une mise à jour de votre exemple qui résout ces problèmes:

public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>
   (string propertyName)
{
    var propertyInfo = typeof(TModel).GetProperty(propertyName);

    var entityParam = Expression.Parameter(typeof(TModel), "e"); 
    Expression columnExpr = Expression.Property(entityParam, propertyInfo);

    if (propertyInfo.PropertyType != typeof(T))
        columnExpr = Expression.Convert(columnExpr, typeof(T));

    return Expression.Lambda<Func<TModel, T>>(columnExpr, entityParam);
}

Cela fera réussir tous les appels suivants:

public static Expression<Func<TModel, T>> GenerateMemberExpression<TModel, T>
   (string propertyName)
{
    var propertyInfo = typeof(TModel).GetProperty(propertyName);

    var entityParam = Expression.Parameter(typeof(TModel), "e"); 
    Expression columnExpr = Expression.Property(entityParam, propertyInfo);

    if (propertyInfo.PropertyType != typeof(T))
        columnExpr = Expression.Convert(columnExpr, typeof(T));

    return Expression.Lambda<Func<TModel, T>>(columnExpr, entityParam);
}

Réponse populaire

Essayez de convertir manuellement la valeur du champ en cas de passage d'un "objet". Par exemple:

var columnExpr = Expression.MakeMemberAccess(entityParam, fieldPropertyInfo); // {e.fieldName}
if (T.GetType().Equals(typeof(object)))
{
    columnExpr = Expression.Convert(columnExpr, typeof(object));
}

J'espère que ceci vous aidera.




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