Extrait un morceau de lambda pour l'expression dans select

c# expression expression-trees lambda linq-to-entities

Question

Je peux extraire et réutiliser toute l'expression comme ça:

Expression<Func<User, int>> userExpression = x => x.Roles.Count()

mais est-il possible d'extraire un peu comment seulement x.Roles.Count() partie et l'utiliser dans le contexte de l' Expression<Func<User, T>>

Ce que j'essaie de réaliser est de réutiliser cette partie sur différents éléments sélectionnés, comme:

Expression<Func<User, int>> userExpression = x => x.Roles.Count()

et

Expression<Func<User, int>> userExpression = x => x.Roles.Count()

Ainsi, ce que roleCountPartOfExpression est censé être dans ce cas devrait être pris en charge dans LINQ to Entities (créer une méthode où je passerai à User, où return user.Roles.Count() ne fonctionnera pas), je ne peux pas non plus créer une expression pour select Expression<Func<User, AnotherClass>> car dans ce cas, je Expression<Func<User, AnotherClass>> créer Expression<Func<User, OneMoreAnotherClass>> , ce qui rompra mon objectif de "réutilisabilité".

Réponse acceptée

Si vous compilez vers un Func<User, int> , vous pouvez l'appeler dans d'autres domaines, comme suit:

Expression<Func<User, int>> userExpression = x => x.Roles.Count();

Func<User,int> userFunc = userExpression.Compile();

users.Select(x => new AnotherClass { RoleCount = userFunc(x) });

Ou simplement définir comme un Func pour commencer:

Expression<Func<User, int>> userExpression = x => x.Roles.Count();

Func<User,int> userFunc = userExpression.Compile();

users.Select(x => new AnotherClass { RoleCount = userFunc(x) });

Est-ce que cela utilise Linq-to-Objects ou autre chose? Si vous avez besoin de le garder comme une Expression parce que l' Expression se transforme en quelque chose d' autre (comme un appel SQL), vous pouvez utiliser LinqKit de AsExpandable comme ceci:

Expression<Func<User, int>> userExpression = x => x.Roles.Count();

Func<User,int> userFunc = userExpression.Compile();

users.Select(x => new AnotherClass { RoleCount = userFunc(x) });

Réponse populaire

Nous pouvons créer une méthode Combine capable de prendre un sélecteur pour un objet, puis un autre sélecteur qui prend également la sortie du premier sélecteur pour produire un résultat final:

public static Expression<Func<TFirstParam, TResult>>
    Combine<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], param)
        .Replace(second.Parameters[1], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

Ceci utilise la méthode d'assistance suivante pour remplacer toutes les occurrences d'une expression par une autre:

public static Expression<Func<TFirstParam, TResult>>
    Combine<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], param)
        .Replace(second.Parameters[1], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

Maintenant nous pouvons écrire:

public static Expression<Func<TFirstParam, TResult>>
    Combine<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], param)
        .Replace(second.Parameters[1], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}



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