Die Methoden Select
und Where
sind in Linq verfügbar. Was sollte jeder Entwickler über diese beiden Methoden wissen? Zum Beispiel: wann man eins über dem anderen verwendet, welche Vorteile es hat, eines über dem anderen zu verwenden usw.
Die Methoden Select
und Where
sind in Linq verfügbar. Was sollte jeder Entwickler über diese beiden Methoden wissen? Zum Beispiel: wann man eins über dem anderen verwendet, welche Vorteile es hat, eines über dem anderen zu verwenden usw.
Antworten:
Wo
findet übereinstimmende Elemente und gibt nur diejenigen zurück, die übereinstimmen ( Filterung ).
-> rein IEnumerable<A>
, IEnumerable<A>
raus
Wählen
Gibt etwas für alle Elemente in der Quelle zurück ( Projektion / Transformation ). Das etwas könnte das Objekt selbst sein, ist aber normalerweise eine Art Projektion.
-> rein IEnumerable<A>
, IEnumerable<B>
raus
Select
gibt immer die gleiche Anzahl von Elementen in der Liste zurück (unabhängig von einer Filterbedingung, die Sie möglicherweise haben). Where
kann abhängig von Ihrer Filterbedingung weniger Elemente zurückgeben.
Where == filter
undSelect == map
Select und Where sind zwei völlig unterschiedliche Operatoren, die auf IEnumerable s einwirken .
Der erste ist ein Projektionsoperator , während der letzte ein Restriktionsoperator ist .
Ein interessanter Weg, um einen Einblick in das Verhalten solcher Operatoren zu erhalten, besteht darin, einen Blick auf ihren "Funktionstyp" zu werfen.
Wählen Sie: (IEnumerable <T1>, Func <T1, T2>) → IEnumerable <T2> ; Als Eingabe wird sowohl eine IEnumerable mit Elementen vom Typ T1 als auch eine Funktion verwendet, die Elemente vom Typ T1 in Elemente vom Typ T2 umwandelt. Die Ausgabe ist eine IEnumerable, die Elemente vom Typ T2 enthält.
Daraus lässt sich leicht ableiten, dass dieser Operator seine Ausgabe erzeugt, indem er die Eingabefunktion auf jedes Element der Eingabe IEnumerable anwendet und die Ergebnisse in eine neue IEnumerable einschließt.
Unter Verwendung einer mathematischen Notation nimmt es als Eingabe (a, b, c, ...): IEnumerable <T1> und f: T1 → T2 und erzeugt (f (a), f (b), f (c) , ...): IEnumerable <T2>
Wobei: (IEnumerable <T1>, Func <T1, bool>) → IEnumerable <T1> ; Dieser verwendet eine IEnumerable, die Elemente vom Typ T1 und ein Prädikat für T1 enthält (dh eine Funktion, die ein boolesches Ergebnis für eine Eingabe vom Typ T1 erzeugt). Sie sehen, dass die Ausgabe auch eine IEnumerable ist, die Elemente vom Typ T1 enthält.
Diesmal würde man vermuten, dass ein Element der Eingabe IEnumerable in der Ausgabe IEnumerable vorhanden sein wird, abhängig vom Ergebnis der Anwendung des Prädikats auf das Element. Wenn Sie die Semantik des Operatornamens hinzufügen, können Sie sicher sein, dass die Ausgabe IEnumerable erzeugt wird, indem Sie aus der Eingabe nur die Elemente entnehmen, die bei der Anwendung des Prädikats als wahr ausgewertet werden.
Leute mit funktionalem Programmierhintergrund denken normalerweise so. Sie können daraus ableiten (oder zumindest raten ...), was ein Operator tut, indem Sie nur seinen Typ betrachten!
Versuchen Sie als Übung, andere von LINQ auf IEnumerables eingeführte Operatoren zu betrachten und ihr Verhalten abzuleiten, bevor Sie sich die Dokumentation ansehen!
Sie sind verschieden:
Select
dreht sich alles um Transformation .
Where
dreht sich alles um das Filtern .
Select ordnet eine Aufzählung einer neuen Struktur zu. Wenn Sie eine Auswahl für eine IEnumerable durchführen, erhalten Sie ein Array mit der gleichen Anzahl von Elementen, jedoch einem anderen Typ, abhängig von der von Ihnen angegebenen Zuordnung. Wobei die IEnumerable so filtert, dass Sie eine Teilmenge der ursprünglichen IEnumerable erhalten.
Where
~ = Filter
Select
~ = Karte
Beide kehren zurück IEnumerable<T>
Wenn Sie wissen, wie sie Where implementiert haben, und Erweiterungsmethoden auswählen, können Sie vorhersagen, was es tut ... Ich habe versucht, Where zu implementieren und Erweiterungsmethoden auszuwählen ... Sie können es sich ansehen ...
Wo Implementierung ::
public static IEnumerable<Tsource> Where<Tsource> ( this IEnumerable<Tsource> a , Func<Tsource , bool> Method )
{
foreach ( var data in a )
{
//If the lambda Expression(delegate) returns "true" Then return the Data. (use 'yield' for deferred return)
if ( Method.Invoke ( data ) )
{
yield return data;
}
}
}
Implementierung auswählen ::
public static IEnumerable<TResult> Select<TSource , TResult> ( this IEnumerable<TSource> a , Func<TSource , TResult> Method )
{
foreach ( var item in a )
{
//Each iteration call the delegate and return the Data back.(use 'yield' for deferred return)
yield return Method.Invoke ( item );
}
}
Meine Implementierung funktioniert für jede Sammlung einwandfrei ... Sie unterscheidet sich jedoch von den von Microsoft implementierten Erweiterungsmethoden, da sie Ausdrucksbäume verwenden, um dieselbe zu implementieren.
Im Fall von Select it können Sie einer IEnumerable einer neuen Struktur zuordnen.
A.Select(x=>new X{UID=x.uid, UNAME=x.uname})
//input as [IEnumerable<A>] --------> return output as [IEnumerable<X> ]
Wenn () als Filter für IEnumerable fungiert, wird das Ergebnis auf der Grundlage der where-Klausel zurückgegeben.
A.Where(x=>x.uid!=0) //input as [IEnumerable<A>] --------> return output as [IEnumerable<A> ]