from-Klausel (C#-Referenz)
Ein Abfrageausdruck muss mit einer from-Klausel beginnen. Darüber hinaus kann ein Abfrageausdruck Unterabfragen enthalten, die auch mit einer from-Klausel beginnen. Die from-Klausel gibt Folgendes an:
Die Datenquelle, für die die Abfrage oder Unterabfrage ausgeführt wird.
Eine lokale Bereichsvariable, die jedes Element in der Quellsequenz darstellt.
Sowohl die Bereichsvariable als auch die Datenquelle sind stark typisiert. Auf die in der from-Klausel verwiesene Datenquelle muss vom Typ IEnumerable, IEnumerable oder von einem abgeleiteten Typ wie IQueryable sein.
Im folgenden Beispiel ist numbers die Datenquelle, und num ist die Bereichsvariable. Beachten Sie, dass beide Variablen stark typisiert sind, obwohl sogar das var-Schlüsselwort verwendet wird.
class LowNums
{
static void Main()
{
// A simple data source.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
// Create the query.
// lowNums is an IEnumerable<int>
var lowNums = from num in numbers
where num < 5
select num;
// Execute the query.
foreach (int i in lowNums)
{
Console.Write(i + " ");
}
}
}
// Output: 4 1 3 2 0
Die Bereichsvariable
Der Compiler leitet den Typ der Bereichsvariablen ab, wenn die Datenquelle IEnumerable implementiert. Wenn die Quelle beispielsweise vom Typ IEnumerable<Customer> ist, wird die Bereichsvariable als Customer abgeleitet. Sie müssen den Typ nur explizit angeben, wenn die Quelle ein nicht-generischer IEnumerable-Typ wie z. B. ArrayList ist. Weitere Informationen hierzu finden Sie unter Gewusst wie: Abfragen von ArrayList mit LINQ.
Im vorherigen Beispiel wird num als Typ int abgeleitet. Da die Bereichsvariable eine sehr starke Typisierung aufweist, können Sie für sie Methoden aufrufen oder sie in anderen Operationen verwenden. Anstatt z. B. select num zu schreiben, könnten Sie select num.ToString() schreiben, sodass der Abfrageausdruck eine Sequenz von Zeichenfolgen anstelle von Ganzzahlen zurückgibt. Sie könnten auch select n + 10 schreiben, damit der Ausdruck die Sequenz 14, 11, 13, 12, 10 zurückgibt. Weitere Informationen finden Sie unter select-Klausel (C#-Referenz).
Die Bereichsvariable entspricht einer Iterationsvariablen in einer foreach-Anweisung mit einer wichtigen Ausnahme: Eine Bereichsvariable speichert niemals Daten aus der Quelle. Sie ist nur ein syntaktisches Hilfsmittel, mit dem die Abfrage beschreiben kann, was eintritt, wenn die Abfrage ausgeführt wird. Weitere Informationen hierzu finden Sie unter Einführung in LINQ-Abfragen (C#).
Zusammengesetzte from-Klauseln
In einigen Fällen kann jedes Element in der Quellsequenz selbst eine Sequenz sein oder eine Sequenz enthalten. Ihre Datenquelle kann beispielsweise ein IEnumerable<Student> sein, wobei jedes Student-Objekt in der Sequenz eine Liste der Testergebnisse enthält. Um auf die innere Liste innerhalb jedes Student-Elements zuzugreifen, können Sie zusammengesetzte from-Klauseln verwenden. Die Technik entspricht dem Verwenden von geschachtelten foreach-Anweisungen. Sie können die where-Klausel oder die orderby-Klausel zu einer der beiden from-Klauseln hinzufügen, um die Ergebnisse zu filtern. Das folgende Beispiel enthält eine Sequenz von Student-Objekten, von denen jedes eine innere List mit Ganzzahlen enthält, die die Testergebnisse darstellen. Um auf die innere Liste zuzugreifen, verwenden Sie eine zusammengesetzte from-Klausel. Bei Bedarf können Sie Klauseln zwischen den beiden from-Klauseln einfügen.
class CompoundFrom
{
// The element type of the data source.
public class Student
{
public string LastName { get; set; }
public List<int> Scores {get; set;}
}
static void Main()
{
// Use a collection initializer to create the data source. Note that
// each element in the list contains an inner sequence of scores.
List<Student> students = new List<Student>
{
new Student {LastName="Omelchenko", Scores= new List<int> {97, 72, 81, 60}},
new Student {LastName="O'Donnell", Scores= new List<int> {75, 84, 91, 39}},
new Student {LastName="Mortensen", Scores= new List<int> {88, 94, 65, 85}},
new Student {LastName="Garcia", Scores= new List<int> {97, 89, 85, 82}},
new Student {LastName="Beebe", Scores= new List<int> {35, 72, 91, 70}}
};
// Use a compound from to access the inner sequence within each element.
// Note the similarity to a nested foreach statement.
var scoreQuery = from student in students
from score in student.Scores
where score > 90
select new { Last = student.LastName, score };
// Execute the queries.
Console.WriteLine("scoreQuery:");
// Rest the mouse pointer on scoreQuery in the following line to
// see its type. The type is IEnumerable<'a>, where 'a is an
// anonymous type defined as new {string Last, int score}. That is,
// each instance of this anonymous type has two members, a string
// (Last) and an int (score).
foreach (var student in scoreQuery)
{
Console.WriteLine("{0} Score: {1}", student.Last, student.score);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/*
scoreQuery:
Omelchenko Score: 97
O'Donnell Score: 91
Mortensen Score: 94
Garcia Score: 97
Beebe Score: 91
*/
Verwenden von mehreren from-Klauseln zum Ausführen von Joins
Eine zusammengesetzte from-Klausel wird zum Zugriff auf innere Auflistungen in einer einzelnen Datenquelle verwendet. Eine Abfrage kann jedoch auch mehrere from-Klauseln enthalten, die ergänzende Abfragen aus unabhängigen Datenquellen generieren. Mit dieser Technik können Sie bestimmte Typen von Joinoperationen durchführen, die beim Einsatz der join-Klausel nicht möglich sind.
Das folgende Beispiel veranschaulicht, wie zwei from-Klauseln verwendet werden können, um einen vollständigen Cross Join zweier Datenquellen zu bilden.
class CompoundFrom2
{
static void Main()
{
char[] upperCase = { 'A', 'B', 'C' };
char[] lowerCase = { 'x', 'y', 'z' };
// The type of joinQuery1 is IEnumerable<'a>, where 'a
// indicates an anonymous type. This anonymous type has two
// members, upper and lower, both of type char.
var joinQuery1 =
from upper in upperCase
from lower in lowerCase
select new { upper, lower };
// The type of joinQuery2 is IEnumerable<'a>, where 'a
// indicates an anonymous type. This anonymous type has two
// members, upper and lower, both of type char.
var joinQuery2 =
from lower in lowerCase
where lower != 'x'
from upper in upperCase
select new { lower, upper };
// Execute the queries.
Console.WriteLine("Cross join:");
// Rest the mouse pointer on joinQuery1 to verify its type.
foreach (var pair in joinQuery1)
{
Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
}
Console.WriteLine("Filtered non-equijoin:");
// Rest the mouse pointer over joinQuery2 to verify its type.
foreach (var pair in joinQuery2)
{
Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Cross join:
A is matched to x
A is matched to y
A is matched to z
B is matched to x
B is matched to y
B is matched to z
C is matched to x
C is matched to y
C is matched to z
Filtered non-equijoin:
y is matched to A
y is matched to B
y is matched to C
z is matched to A
z is matched to B
z is matched to C
*/
Weitere Informationen zu Joinoperationen mit mehreren from-Klauseln finden Sie unter Gewusst wie: Ausführen von benutzerdefinierten Verknüpfungsoperationen (C#-Programmierhandbuch).
Siehe auch
Konzepte
LINQ-Abfrageausdrücke (C#-Programmierhandbuch)