from (Cláusula, Referencia de C#)

Actualización: noviembre 2007

Una expresión de consulta debe comenzar con una cláusula from. Además, una expresión de consulta puede contener subconsultas, que también comienzan con una cláusula from. La cláusula from especifica lo siguiente:

  • El origen de datos en el que se ejecutará la consulta o subconsulta.

  • Una variable de rango local que representa cada elemento en la secuencia de origen.

La variable de rango y el origen de datos tienen establecimiento inflexible de tipos. El origen de datos al que se hace referencia en la cláusula from debe tener un tipo IEnumerable, IEnumerable<T> o un tipo derivado, como IQueryable<T>.

En el ejemplo siguiente, numbers es el origen de datos y num es la variable de rango. Observe que ambas variables tienen establecimiento inflexible de tipos aunque se use la palabra clave 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

Variable de rango (Range)

El compilador deduce el tipo de la variable de rango cuando el origen de datos implementa IEnumerable<T>. Por ejemplo, si el origen tiene un tipo IEnumerable<Customer>, se deduce que la variable de rango es Customer. La única ocasión en que se debe especificar explícitamente el tipo es cuando el origen es un tipo IEnumerable no genérico, como ArrayList. Para obtener más información, vea Cómo: Consultar un objeto ArrayList con LINQ.

En el ejemplo anterior, se deduce que num es de tipo int. Dado que la variable de rango tiene establecimiento inflexible de tipos, se puede llamar a métodos en ella o usar en otras operaciones. Por ejemplo, en lugar de escribir select num, podría escribir select num.ToString() para hacer que la expresión de consulta devuelva una secuencia de cadenas en lugar de enteros. También podría escribir select n + 10 para hacer que la expresión devuelva la secuencia 14, 11, 13, 12, 10. Para obtener más información, vea select (Cláusula, Referencia de C#).

La variable de rango es como una variable de iteración en una instrucción foreach, salvo por una diferencia muy importante: una variable de rango nunca almacena realmente los datos del origen. Es simplemente una comodidad sintáctica que permite a la consulta describir lo que ocurrirá cuando se ejecute. Para obtener más información, vea Introducción a consultas con LINQ.

Cláusulas From compuestas

En algunos casos, cada elemento de la secuencia de origen puede ser en sí mismo una secuencia o contenerla. Por ejemplo, el origen de datos puede ser un IEnumerable<Student>, donde cada objeto de estudiante de la secuencia contiene una lista de puntuaciones de exámenes. Para tener acceso a la lista interna de cada elemento Student, puede utilizar cláusulas from compuestas. La técnica es como utilizar instrucciones foreach anidadas. Puede agregar cláusulas where u orderby a cualquier cláusula from para filtrar los resultados. En el ejemplo siguiente se muestra una secuencia de objetos Student, cada uno de los cuales contiene un objeto List interno de enteros que representan las puntuaciones de los exámenes. Para tener acceso a la lista interna, utilice una cláusula from compuesta. Puede insertar cláusulas entre las dos cláusulas from si es necesario.

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:");
        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
*/

Utilizar varias cláusulas From para realizar combinaciones

Para tener acceso a las colecciones internas de un origen de datos único, se utiliza una cláusula from compuesta. Sin embargo, una consulta también puede contener varias cláusulas from que generen consultas complementarias de orígenes de datos independientes. Esta técnica permite realizar ciertos tipos de operaciones de combinación que no son posibles con la cláusula Join.

En el ejemplo siguiente se muestra cómo usar dos cláusulas from para formar una combinación cruzada completa de dos orígenes de datos.

class CompoundFrom2
{
    static void Main()
    {              
        char[] upperCase = { 'A', 'B', 'C'};
        char[] lowerCase = { 'x', 'y', 'z'};

        var joinQuery1 =
            from upper in upperCase
            from lower in lowerCase
                select new { upper, lower};

        var joinQuery2 =
            from lower in lowerCase
            where lower != 'x'
            from upper in upperCase
            select new { lower, upper };


        // Execute the queries.
        Console.WriteLine("Cross join:");
        foreach (var pair in joinQuery1)
        {
            Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
        }

        Console.WriteLine("Filtered non-equijoin:");
        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 obtener más información sobre las operaciones de combinación que utilizan varias cláusulas from, vea Cómo: Realizar operaciones de combinación personalizadas (Guía de programación de C#).

Vea también

Conceptos

Expresiones de consultas con LINQ (Guía de programación de C#)

Otros recursos

Palabras clave de consultas (Referencia de C#)