from 절(C# 참조)from clause (C# Reference)

쿼리 식은 from 절로 시작해야 합니다.A query expression must begin with a from clause. 또한 쿼리 식은 from 절로 시작하는 하위 쿼리를 포함할 수 있습니다.Additionally, a query expression can contain sub-queries, which also begin with a from clause. from 절은 다음 내용을 지정합니다.The from clause specifies the following:

  • 쿼리 또는 하위 쿼리가 실행될 데이터 소스.The data source on which the query or sub-query will be run.

  • 소스 시퀀스의 각 요소를 나타내는 지역 범위 변수.A local range variable that represents each element in the source sequence.

범위 변수 및 데이터 소스 모두 강력한 형식입니다.Both the range variable and the data source are strongly typed. from 절에서 참조되는 데이터 소스는 IEnumerable 또는 IEnumerable<T> 형식이거나 IQueryable<T>와 같은 파생 형식이어야 합니다.The data source referenced in the from clause must have a type of IEnumerable, IEnumerable<T>, or a derived type such as IQueryable<T>.

다음 예제에서 numbers는 데이터 소스이고 num은 범위 변수입니다.In the following example, numbers is the data source and num is the range variable. var 키워드가 사용되어도 두 변수는 모두 강력한 형식입니다.Note that both variables are strongly typed even though the var keyword is used.

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

범위 변수The range variable

컴파일러는 데이터 소스가 IEnumerable<T>을 구현할 경우 범위 변수의 형식을 유추합니다.The compiler infers the type of the range variable when the data source implements IEnumerable<T>. 예를 들어, 소스의 형식이 IEnumerable<Customer>일 경우 범위 변수는 Customer로 유추됩니다.For example, if the source has a type of IEnumerable<Customer>, then the range variable is inferred to be Customer. 소스가 ArrayList와 같이 제네릭이 아닌 IEnumerable 형식인 경우에만 형식을 명시적으로 지정하면 됩니다.The only time that you must specify the type explicitly is when the source is a non-generic IEnumerable type such as ArrayList. 자세한 내용은 방법: LINQ를 사용하여 ArrayList 쿼리.For more information, see How to: Query an ArrayList with LINQ.

위의 예제에서 numint 형식으로 유추됩니다.In the previous example num is inferred to be of type int. 범위 변수가 강력한 형식이므로 범위 변수에서 메서드를 호출하거나 다른 작업에서 범위 변수를 사용할 수 있습니다.Because the range variable is strongly typed, you can call methods on it or use it in other operations. 예를 들어 select num을 작성하는 대신에 select num.ToString()을 작성하여 쿼리 식에서 정수 대신 문자열 시퀀스를 반환하게 할 수 있습니다.For example, instead of writing select num, you could write select num.ToString() to cause the query expression to return a sequence of strings instead of integers. 또는 select num + 10을 작성하여 식에서 14, 11, 13, 12, 10 시퀀스를 반환하게 할 수 있습니다.Or you could write select num + 10 to cause the expression to return the sequence 14, 11, 13, 12, 10. 자세한 내용은 select 절을 참조하세요.For more information, see select clause.

범위 변수가 소스의 데이터를 실제로 저장하지 않는다는 매우 중요한 한 가지 차이점을 제외하면 범위 변수는 foreach 문의 반복 변수와 같습니다.The range variable is like an iteration variable in a foreach statement except for one very important difference: a range variable never actually stores data from the source. 범위 변수는 단순히 쿼리 실행 시에 발생하는 작업을 쿼리에서 설명할 수 있게 하는 구문상의 편리함을 제공합니다.It's just a syntactic convenience that enables the query to describe what will occur when the query is executed. 자세한 내용은 LINQ 쿼리 소개(C#)를 참조하세요.For more information, see Introduction to LINQ Queries (C#).

복합 from 절Compound from clauses

경우에 따라 소스 시퀀스의 각 요소 자체가 시퀀스이거나 시퀀스를 포함할 수 있습니다.In some cases, each element in the source sequence may itself be either a sequence or contain a sequence. 예를 들어, 시퀀스의 각 학생 개체에 테스트 점수 목록이 포함된 IEnumerable<Student>가 데이터 소스일 수 있습니다.For example, your data source may be an IEnumerable<Student> where each student object in the sequence contains a list of test scores. Student 요소 내의 내부 목록에 액세스하려면 복합 from 절을 사용합니다.To access the inner list within each Student element, you can use compound from clauses. 이 기술은 중첩된 foreach 문을 사용하는 것과 같습니다.The technique is like using nested foreach statements. where 또는 orderby 절을 둘 중 하나의 from 절에 추가하여 결과를 필터링할 수 있습니다.You can add where or orderby clauses to either from clause to filter the results. 다음 예제에서는 테스트 점수를 나타내는 정수의 내부 List를 각각 포함하는 Student 개체의 시퀀스를 보여 줍니다.The following example shows a sequence of Student objects, each of which contains an inner List of integers representing test scores. 내부 목록에 액세스하려면 복합 from 절을 사용합니다.To access the inner list, use a compound from clause. 필요한 경우 두 from 절 사이에 다른 절을 삽입할 수 있습니다.You can insert clauses between the two from clauses if necessary.

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
*/

여러 from 절을 사용하여 조인 수행Using Multiple from Clauses to Perform Joins

복합 from 절은 단일 데이터 소스의 내부 컬렉션에 액세스하는 데 사용됩니다.A compound from clause is used to access inner collections in a single data source. 그러나 독립 데이터 소스의 추가 쿼리를 생성하는 여러 from 절이 쿼리에 포함될 수도 있습니다.However, a query can also contain multiple from clauses that generate supplemental queries from independent data sources. 이 기술을 사용하면 join 절로 수행할 수 없는 특정 형식의 조인 작업을 수행할 수 있습니다.This technique enables you to perform certain types of join operations that are not possible by using the join clause.

다음 예제는 두 개의 from 절을 사용하여 두 개의 데이터 소스의 완전한 크로스 조인을 구성하는 방법을 보여 줍니다.The following example shows how two from clauses can be used to form a complete cross join of two data sources.

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
        */

여러 from 절을 사용하는 조인 작업에 대한 자세한 내용은 왼쪽 우선 외부 조인 수행을 참조하세요.For more information about join operations that use multiple from clauses, see Perform left outer joins.

참고 항목See also