2015-08-16 1 views
0

Dans LINQ to Objects, existe-t-il un moyen d'identifier les entités/objets qualifiés/disqualifiés à chaque filtre?Comment intercepter les filtres Linq

Pour exemple) Disons que j'ai une entité appelée « Produit » (Id, nom) et si i entrée 100 produits dans une requête Linq qui a 5 « où » conditon et obtenez 20 produits en sortie.

Existe-t-il un moyen d'identifier quel produit a été filtré à quelle condition?

+0

Merci pour la réponse – memumani

+0

C'est ce que vous cherchiez? (En outre, il semble que vous avez commenté votre question au lieu de sur ma réponse: P) –

+0

Merci pour la réponse. Diverses requêtes sont à différents endroits où je veux enregistrer ces informations. Au lieu d'apporter des changements à plusieurs endroits, y a-t-il une approche générative pour le garder au même endroit ou avec des changements minimes? – memumani

Répondre

0

Aspect important reste ce que vous voulez faire avec les données filtrées à chaque niveau, comme vous le savez, linq aux objets, utiliser un mécanisme de chaînage, où résultat d'un niveau est alimenté comme une entrée au niveau suivant, certains comme:

var result = OriginalList.Where(Condition1) - Level1 
         .Where(Condition2) - Level2 
         .Where(Condition3) - Level3 
         .Where(Condition4) - Level4 

Ici, la sortie Level1 est une entrée pour Level2, et ainsi de suite. S'il n'y a pas de données à un certain niveau, cela garantira que l'ensemble de niveaux suivant est ignoré en interne, comme toute condition sur l'ensemble vide et l'ensemble vide.

Pour obtenir un résultat à tous les niveaux, vous devez les séparer dans des variables distinctes et faire l'enchaînement sur votre propre, en fonction des exigences conditionnelles que vous pourriez avoir, quelque chose comme:

var result1 = OriginalList.Where(Condition1) 
var result2 = result1.Where(Condition2) 

Donc et ainsi de suite, où avant d'appliquer la clause where sur le résultat 1, vous pouvez appliquer une vérification conditionnelle. Si je comprends bien, vous voudrez peut-être un enregistreur standard pour imprimer les détails à chacun des sous-point, mettre en œuvre la méthode d'extension comme suit:

public static class LoggingExtension 
{ 
    public static void Log<dynamic>(IEnumerable<dynamic> collection) 
    { 
    // Use the favorite logger to log the collection here 
    } 
} 

Si j'utilise le code ci-dessus pour result1 d'impression, result2, ce que vous avez besoin est:

var result1 = OriginalList.Where(Condition1) 
     result1.Log(); 
    var result2 = result1.Where(Condition2) 
     result2.Log(); 

J'utilise le type dynamique dans la méthode d'extension ci-dessus, afin d'éviter l'extraction du type d'un anonyme, en interne, vous pouvez taper jeter à ne importe quel type et l'utiliser dans l'enregistreur

2

Cela peut probablement être généralisé, mais vous pouvez le faire ce. Je ne vois tout simplement pas le cas d'utilisation pour cela. Utilisez ToLookup() pour partitionner vos requêtes. Les éléments "disqualifiés" seront regroupés sous le groupe false et vous pourrez continuer votre requête avec le groupe true.

par exemple,

var numbers = Enumerable.Range(0, 100); 
var p1 = numbers.ToLookup(n1 => n1 < 50); 
// p1[false] -> [ 50, 51, 52, ... ] 
var p2 = p1[true].ToLookup(n2 => n2 % 2 == 0); 
// p2[false] -> [ 1, 3, 5, 7, ... ] 
var p3 = p2[true]... // and so on 
0

Alors que tout le monde jusqu'à présent vous a montré comment faire la chose évidente, à savoir regrouper vos données en plusieurs parties correspondant à une condition, personne ne vous adresse ce que vous demandez en fait

identifier quel produit a été filtré où condition

uestion est comment vont se connecter la condition où?

Cela peut sembler trivial de le faire, mais vous allez échouer car vous ne pourrez pas obtenir une représentation sous forme de chaîne de l'objet Func qui a été utilisé. C'est un délégué, c'est-à-direcode compilé, et vous devrez le désosser à l'exécution pour obtenir le code source. C'est en soi assez difficile, mais si le compilateur a choisi d'optimiser le code, vous êtes perdu.

Seulement si vous êtes prêt à créer votre propre méthode d'extension (s) qui utilisent des expressions au lieu de Func s, vous serez en mesure de vous connecter où l'état, car l'expression est constituée de jetons qui peuvent facilement être 'ToString-ed' à l'exécution.

Par exemple:

public static IEnumerable<T> WhereEx<T>(this IEnumerable<T> sequence, Expression<Func<T, bool>> condition) 
{ 
    var logString = condition.Body.ToString(); 
    foreach (T item in sequence.Where(condition.Compile())) 
    { 
     yield return item; 
     // logging hook here, this one simply dumps in Linqpad. 
     string.Format("Item '{0}' meets '{1}'", item, logString).Dump(); 
    } 
} 

Maintenant, vous êtes vraiment intercepter le filtre. Mais vous n'avez aucune idée où dans le code le filtre est appliqué. Si vous voulez également enregistrer des cadres de pile, les performances vont probablement devenir un problème (réflexion!), Car il est déjà sous pression en compilant l'expression à chaque fois. Ensuite, la consignation doit être une opération asynchrone impliquant une file d'attente de journalisation thread-safe.