Le paramètre d'expression n'est pas défini

c# expression expression-trees linq linq-expressions

Question

J'essaie d'exécuter une requête sur une liste pour obtenir des résultats immédiats à l'aide d'une expression définie ailleurs dans le code, tandis qu'un second thread s'éteint et l'utilise pour obtenir l'ensemble des résultats d'une base de données dans une requête Linq.

Je sais que l'expression elle-même est acceptable, car lorsque je l'envoie par le serveur côté serveur et que je l'applique à un IQueriable, cela fonctionnera. Cependant, lorsqu'elle est appliquée côté client, l'erreur suivante est générée:

System.InvalidOperationException: 'variable' item 'de type' MissionControlSuite.Shared.Interface.Model.IBox 'référencé à partir de scope' ', mais il n'est pas défini'

Ce code qui effectue le filtrage:

public abstract class GridWithPaging<T> where T : class
{
    List<T> _items

    public Expression<Func<T, bool>> Filter { get; set; }
    public ObservableCollection<IGridFilter<T>> Filters { get; set; }

    // more code skipped for breveity

    public void FiltersChanged(object sender, EventArgs e)
    {
        Expression<Func<T, bool>> combined = item => true;
        foreach (var filter in Filters)
            combined = Expression.Lambda<Func<T, bool>>(
                Expression.AndAlso(filter.Expression.Body, combined.Body),
                combined.Parameters.Single());

        Filter = combined;
        NotifyPropertyChanged("Filter");
    }

    public void AddFilter(IGridFilter<T> filter)
    {
        Filters.Add(filter);
        NotifyPropertyChanged("Filters");
    }

    private void DoFiltering(int start)
    {
        var newView = _items.Skip(start);
        if(Filter != null)
            newView = newView.AsQueryable().Where(Filter);

        //some more code that acts on the filtered list
    }
}

L'expression est placée ailleurs comme ceci:

Expression<Func<IBox, bool>> expression = item => item.BoxId.Contains(v);

var filter = new GridFilter<IBox>()
{
    Name = string.Format("{0} contains {1}", Property, Value),
    Expression = expression
};

Grid.AddFilter(filter);

Réponse acceptée

Cette réponse vous aidera à: Combiner deux expressions (Expression <Func <T, bool >>)

Pour résumer: le problème est que les paramètres, bien que portant le même nom, ne sont pas la même instance de ParameterExpression - qui est incluse dans le commentaire de cette réponse .

La solution consiste à utiliser un visiteur (code copié à partir d'un article lié):

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1,
    Expression<Func<T, bool>> expr2)
{
    var parameter = Expression.Parameter(typeof (T));

    var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
    var left = leftVisitor.Visit(expr1.Body);

    var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
    var right = rightVisitor.Visit(expr2.Body);

    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(left, right), parameter);
}



private class ReplaceExpressionVisitor
    : ExpressionVisitor
{
    private readonly Expression _oldValue;
    private readonly Expression _newValue;

    public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
    {
        _oldValue = oldValue;
        _newValue = newValue;
    }

    public override Expression Visit(Expression node)
    {
        if (node == _oldValue)
            return _newValue;
        return base.Visit(node);
    }
}

A noter également: le fournisseur ORM (ou un autre IQueryable que vous utilisez) fonctionne sans doute parce qu'il se traduit par ce texte directement à, alors que l' exécution ( Invoke ING) ce LambdaExpression d'une manière provoque l'erreur car il est plus stricte,. Certains IQueryable peuvent également accepter des paramètres de string simples et les analyser par eux-mêmes, ce qui devrait indiquer qu'ils disposent d'un plus grand nombre d'entrées acceptables.



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