Cláusula from (Referência de C#)

Uma expressão de consulta deve começar com uma cláusula from. Além disso, uma expressão de consulta pode conter subconsultas, que também começam com uma cláusula from. A cláusula from especifica o seguinte:

  • A fonte de dados na qual a consulta ou subconsulta será executada.

  • Uma variável de intervalo local que representa cada elemento na sequência de origem.

A variável de intervalo e a fonte de dados são fortemente tipadas. A fonte de dados referenciada na cláusula from deve ter um tipo de IEnumerable, IEnumerable<T> ou um tipo derivado, por exemplo, IQueryable<T>.

No exemplo a seguir, numbers é a fonte de dados e num é a variável de intervalo. Observe que ambas as variáveis são fortemente tipadas, mesmo com o uso da palavra-chave var.

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

A variável de intervalo

O compilador infere que o tipo da variável de intervalo quando a fonte de dados implementa IEnumerable<T>. Por exemplo, se a fonte tem um tipo de IEnumerable<Customer>, então, a variável de intervalo será inferida como Customer. O tipo deve ser especificado explicitamente somente quando a fonte for um tipo IEnumerable não genérico, como ArrayList. Para obter mais informações, consulte Como consultar um ArrayList com LINQ.

No exemplo anterior, num é inferido como do tipo int. Como a variável de intervalo é fortemente tipada, é possível chamar métodos nela ou usá-la em outras operações. Por exemplo, em vez de gravar select num, grave select num.ToString() para fazer com que a expressão de consulta retorne uma sequência de cadeias de caracteres em vez de números inteiros. Também é possível gravar select num + 10 para fazer com que a expressão retorne a sequência 14, 11, 13, 12, 10. Para obter mais informações, consulte cláusula select.

A variável de intervalo é como uma variável de iteração em uma instrução foreach, com a exceção de uma diferença muito importante: na verdade, uma variável de intervalo nunca armazena dados da fonte. É apenas uma conveniência sintática que habilita a consulta a descrever o que ocorrerá quando ela for executada. Para obter mais informações, consulte Introdução a Consultas de LINQ (C#).

Cláusulas from compostas

Em alguns casos, cada elemento na sequência de origem pode ser uma sequência ou conter uma sequência. Por exemplo, a fonte de dados pode ser um IEnumerable<Student> em que cada objeto do aluno na sequência contenha uma lista de resultados de avaliações. Para acessar a lista interna dentro de cada elemento Student, use cláusulas compostas from. A técnica é parecida com o uso de instruções foreach aninhadas. É possível adicionar cláusulas where ou orderby a qualquer cláusula from para filtrar os resultados. O exemplo a seguir mostra uma sequência de objetos Student, em cada um contém uma List interna de inteiros que representam de resultados de avaliações. Para acessar a lista interna, use uma cláusula composta from. É possível inserir cláusulas entre as duas cláusulas from, se necessário.

class CompoundFrom
{
    // The element type of the data source.
    public class Student
    {
        public required string LastName { get; init; }
        public required List<int> Scores {get; init;}
    }

    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 Student {LastName="Omelchenko", Scores= [97, 72, 81, 60]},
           new Student {LastName="O'Donnell", Scores= [75, 84, 91, 39]},
           new Student {LastName="Mortensen", Scores= [88, 94, 65, 85]},
           new Student {LastName="Garcia", Scores= [97, 89, 85, 82]},
           new Student {LastName="Beebe", Scores= [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);
        }
    }
}
/*
scoreQuery:
Omelchenko Score: 97
O'Donnell Score: 91
Mortensen Score: 94
Garcia Score: 97
Beebe Score: 91
*/

Usando Várias Cláusulas from para Realizar Uniões

Uma cláusula composta from é usada para acessar coleções internas em uma fonte de dados única. No entanto, uma consulta também pode conter várias cláusulas from que geram consultas complementares de fontes de dados independentes. Essa técnica habilita a execução de determinados tipos de operações de união que não são possíveis por meio da cláusula join.

A exemplo a seguir mostra como duas cláusulas from podem ser usadas para formar uma união cruzada completa de duas fontes de dados.

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

Para obter mais informações sobre as operações de união que usam várias cláusulas from, consulte Executar junções externas esquerdas.

Confira também