Frage

Ich versuche, wie so eine Liste von Funktionen zu kombinieren.

Ich habe diese:

Func<int, bool>[] criteria = new Func<int, bool>[3];
criteria[0] = i => i % 2 == 0;
criteria[1] = i => i % 3 == 0;
criteria[2] = i => i % 5 == 0;

Und ich will diese:

Func<int, bool>[] predicates = new Func<int, bool>[3];
predicates[0] = i => i % 2 == 0;
predicates[1] = i => i % 2 == 0 && i % 3 == 0;
predicates[2] = i => i % 2 == 0 && i % 3 == 0 && i % 5 == 0;

Bisher habe ich den folgenden Code bekommen:

Expression<Func<int, bool>>[] results = new Expression<Func<int, bool>>[criteria.Length];

for (int i = 0; i < criteria.Length; i++)
{
    results[i] = f => true;
    for (int j = 0; j <= i; j++)
    {
        Expression<Func<int, bool>> expr = b => criteria[j](b);
        var invokedExpr = Expression.Invoke(
            expr, 
            results[i].Parameters.Cast<Expression>());
        results[i] = Expression.Lambda<Func<int, bool>>(
            Expression.And(results[i].Body, invokedExpr), 
            results[i].Parameters);
    }
}
var predicates = results.Select(e => e.Compile()).ToArray();

Console.WriteLine(predicates[0](6)); // Returns true
Console.WriteLine(predicates[1](6)); // Returns false
Console.WriteLine(predicates[2](6)); // Throws an IndexOutOfRangeException

Weiß jemand, was ich falsch mache?

War es hilfreich?

Lösung

Dies war eine Vermutung, wie ich über diese Dinge etwas wissen, aber das scheint es zu beheben:

Func<int, bool>[] criteria = new Func<int, bool>[3]; 
criteria[0] = i => i % 2 == 0; 
criteria[1] = i => i % 3 == 0; 
criteria[2] = i => i % 5 == 0;
Expression<Func<int, bool>>[] results = new Expression<Func<int, bool>>[criteria.Length];
for (int i = 0; i < criteria.Length; i++)
{
    results[i] = f => true; 
    for (int j = 0; j <= i; j++)
    {
        int ii = i;
        int jj = j;
        Expression<Func<int, bool>> expr = b => criteria[jj](b); 
        var invokedExpr = Expression.Invoke(expr, results[ii].Parameters.Cast<Expression>()); 
        results[ii] = Expression.Lambda<Func<int, bool>>(Expression.And(results[ii].Body, invokedExpr), results[ii].Parameters);
    }
} 
var predicates = results.Select(e => e.Compile()).ToArray(); 

Der Schlüssel ist die Einführung von ‚ii‘ und ‚jj‘ (vielleicht nur ein Angelegenheit, ich habe nicht versucht). Ich glaube, Sie sind in einem Lambda eine veränderbare Variable erfassen und somit, wenn man es schließlich verweist, sind Sie den später mutierte Wert zu sehen, eher als der ursprüngliche Wert.

Andere Tipps

Keine Notwendigkeit, in Ausdrücken zu ziehen ...

    Func<int, bool>[] criteria = new Func<int, bool>[3];
    criteria[0] = i => i % 2 == 0;
    criteria[1] = i => i % 3 == 0;
    criteria[2] = i => i % 5 == 0;

    Func<int, bool>[] predicates = new Func<int, bool>[3];

    predicates[0] = criteria[0];
    for (int i = 1; i < criteria.Length; i++)
    {
        //need j to be an unchanging int, one for each loop execution.
        int j = i;

        predicates[j] = x => predicates[j - 1](x) && criteria[j](x);
    }

    Console.WriteLine(predicates[0](6)); //True
    Console.WriteLine(predicates[1](6)); //True
    Console.WriteLine(predicates[2](6)); //False
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top