Capitulo 3: Introducción a LINQ (Parte 1)

Lección 1: Entendiendo LINQ
Esta lección comienza por dar un ejemplo de una expresión LINQ y algunas sintaxis básicas.

LINQ permite realizar consultas, establecer y transformar las operaciones dentro de la sintaxis del lenguaje de programación. Funciona con cualquier colección que implementa la interfaz IEnumerable o la interfaz genérica IEnumerable <T>, para que pueda ejecutar las consultas LINQ con datos relacional, los datos XML, y la llanura colecciones antiguas.

Entonces, ¿qué se puede hacer con LINQ? La siguiente es una simple consulta LINQ que devuelve la lista de colores que empiezan con la letra B, ordenados.

--------------------------------------VB------------------------------------------

Dim colors() =

{

"Red",

"Brown",

"Orange",

"Yellow",

"Black",

"Green",

"White",

"Violet",

"Blue"

}

Dim results as IEnumerable(Of String)=From c In colors _

Where c.StartsWith("B") _

Order By c _

Select c

--------------------------------------CS------------------------------------------

string[] colors =

{

"Red",

"Brown",

"Orange",

"Yellow",

"Black",

"Green",

"White",

"Violet",

"Blue"

};

IEnumerable<string> results = from c in colors

where c.StartsWith("B")

orderby c

select c;

En el código de ejemplo, se encuentra un "from c in colors" que es similar a un ForEach (C # foreach). C es la variable de bucle que hace referencia a un elemento de la colección de origen de cada una de las iteraciones del ciclo. ¿Cuál es el tipo C y donde se declara c? La variable denominada c se declara en la cláusula from y su tipo es implícitamente establecido.

La cláusula de produce un objeto genérico IEnumerable, que se alimenta en la parte siguiente de la declaración de LINQ (Where). Internamente, la cláusula where tiene el código para iterar sobre los valores entran y sólo los valores que cumplen los criterios especificados serán devueltos, esta también contiene la lógica de filtro, la cláusula order by.
La cláusula select debe ser siempre la última parte de una expresión LINQ. Esto es cuando se quiere devolver todo el objeto con el que empezó (en este caso, c) o algo diferente.

Ejecución diferida
Una consulta LINQ es un objeto genérico IEnumerable de lo que se seleccione. La variable a la que se le asigna este resultado se conoce como la variable de rango. Este es simplemente un objeto de consulta que puede recuperar los datos. LINQ no tiene acceso a los datos de origen hasta que se intenta utilizar el objeto de consulta para trabajar con los resultados. Esto se conoce como ejecución diferida.

La interfaz IEnumerable sólo tiene un método, GetEnumerator, que devuelve un
objeto que implementa la interfaz IEnumerator. La interfaz IEnumerator tiene una propiedad actual, que hace referencia el artículo actual de la colección, y dos métodos, MoveNext yReset. MoveNext mueve al siguiente elemento de la colección. Reset mueve el iterador a su posición inicial, es decir, antes del primer elemento de la colección.

Proveedores de LINQ
La siguiente figura muestra los proveedores de LINQ que se construyen en el. NET Framework.

clip_image001[4]

El proveedor de LINQ funciona como un nivel intermedio entre el almacén de datos y la aplicacion. Además de los proveedores de LINQ incluidos en el. NET Framework, hay muchos otros proveedores de LINQ.

Para crear un proveedor de LINQ, se debe implementar la interfaz IQueryable. Este tiene una propiedad de tipo IQueryProvider (proveedor), que es llamado para iniciar y ejecutar las expresiones LINQ.

Características que componen LINQ
Ahora que hemos visto una expresión LINQ, es hora de ver lo que se añadió a la de. NET Framework para crear LINQ.

Inicializadores de objetos
Se pueden utilizar los inicializadores de objetos para inicializar una o todas las propiedades de este en la misma declaración de una instancia del objeto, pero no estás obligado a escribir constructores personalizados.
Ejemplo de código de una clase “coches” que tiene cinco propiedades, pero no tiene ningún constructor personalizado:

--------------------------------------VB------------------------------------------

Public Class Car

Public Property VIN() As String

Public Property Make() As String

Public Property Model() As String

Public Property Year() As Integer

Public Property Color() As String

End Class

--------------------------------------CS------------------------------------------

public class Car

{

public string VIN { get; set; }

public string Make { get; set; }

public string Model { get; set; }

public int Year { get; set; }

public string Color { get; set; }

}

Para instanciar un objeto Car y rellenar sus propiedades con los datos, se puede hacer algo como lo siguiente:

--------------------------------------VB------------------------------------------

Dim c As New Car()

c.VIN = "ABC123"

c.Make = "Ford"

c.Model = "F-250"

c.Year = 2000

--------------------------------------CS------------------------------------------

Car c = new Car();

c.VIN = "ABC123";

c.Make = "Ford";

c.Model = "F-250";

c.Year = 2000;

Mediante el uso de los inicializadores de objetos, se pueden crear instancias del objeto e inicializar cualquier combinación de propiedades en una sola declaración (en ves de las 5 líneas del ejemplo anterior), como se muestra en el siguiente ejemplo:

--------------------------------------VB------------------------------------------

Dim c As New Car()With{.VIN = "ABC123",.Make = "Ford",.Model = "F-250",.Year = 2000}

--------------------------------------CS------------------------------------------

Car c = new Car() {VIN = "ABC123", Make = "Ford",Model = "F-250", Year = 2000};

Los inicializadores de colección han existido para los arreglos desde la primera versión de. NET Framework, pero ahora se puede inicializar colecciones como ArrayList y List genéricos utilizando la misma sintaxis:

--------------------------------------VB------------------------------------------

Private Function GetCars() As List(Of Car)

Return New List(Of Car) From

{

New Car() With {.VIN = "ABC123",.Make = "Ford",.Model ="F-250",.Year =2000},

New Car() With {.VIN = "DEF123",.Make = "BMW",.Model ="Z-3",.Year = 2005},

New Car() With {.VIN = "DEF456",.Make = "Ford",.Model ="F-150",.Year = 1998}

}

End Function

--------------------------------------CS------------------------------------------

private List<Car> GetCars()

{

return new List<Car>

{

new Car {VIN = "ABC123",Make ="Ford",Model ="F-250", Year =2000},

new Car {VIN = "DEF123",Make ="BMW",Model ="Z-3", Year =2005},

new Car {VIN = "DEF456",Make ="Ford",Model ="F-150", Year =1998}

};

}

¿Cómo son los inicializadores de objeto que se utilizan en LINQ?

Los inicializadores permiten crear algunos tipos de proyecciones en LINQ. Una proyección es una formación o transformación de los datos en una consulta LINQ para producir lo que necesita en la salida con la instrucción de selección en lugar de incluir sólo los datos de origen.

Por ejemplo, si se quiere escribir una consulta LINQ que busque en una lista de colores todos los nombres de los colores que tengan cinco caracteres, ordenados por color, en lugar de devolver un objeto IEnumerable, se puede usar los inicializadores de objeto para devolver un objeto IEnumerable de coches en el que se fija el color del coche:

--------------------------------------VB------------------------------------------

Dim colors() =

{

"Red",

"Brown",

"Orange",

"Yellow",

"Black",

"Green",

"White",

"Violet",

"Blue"

}

Dim fords As IEnumerable(Of Car) = From c In colors

Where c.Length = 5

Order By c

Select New Car() With

{.Make = "Ford",

.Color = c}

For Each car As Car In fords

txtLog.AppendText(String.Format("Car: Make:{0} Color:{1}" _

& Environment.NewLine, car.Make, car.Color))

Next

--------------------------------------CS------------------------------------------

string[] colors =

{

"Red",

"Brown",

"Orange",

"Yellow",

"Black",

"Green",

"White",

"Violet",

"Blue"

};

IEnumerable<Car> fords = from c in colors

where c.Length == 5

orderby c

select new Car()

{

Make = "Ford",

Color = c

};

foreach (Car car in fords)

{

txtLog.AppendText(String.Format("Car: Make:{0} Color:{1}"

+ Environment.NewLine, car.Make, car.Color));

}

La idea de este ejemplo es  construir una colección de coches, cada uno con un color de la colección de colores que coincida con el criterio de cinco letras de largo. La cláusula select crea el  coche e inicializa sus propiedades.  No se podría crear una instancia e inicializar el objeto de coches sin antes escribir un constructor de la clase de coches que toma parámetros Marca y Color.

Declaraciones de variables locales con tipo implícito
En lugar de proporcionar el tipo de la variable, se le está preguntando al compilador que tipo es, en base a lo que está en el lado derecho del signo igual. Eso significa que debe haber un signo de igualdad en la instrucción de declaración, y el lado derecho se debe evaluar como una expresión escrita.

--------------------------------------VB------------------------------------------

Dim cars = GetCars()

--------------------------------------CS------------------------------------------

var cars = GetCars();

Tan pronto como el compilador se da cuenta del tipo que debe ser, no puede cambiarlo. Por lo tanto, se obtiene IntelliSense como si se declara explícitamente el tipo de la variable.

Estas son las reglas para las variables locales de tipo implícito :
■ los valores implícitos se pueden implementar en las variables locales.
■ La instrucción de declaración debe tener un signo igual con una asignación no nula.
■ No se pueden implementar en los parámetros de un método.
Esta característica es necesaria para soportar los tipos anónimos que se utilizan en LINQ.

Tipos anónimos
A veces, se desea agrupar algunos datos de manera temporal, pero no se quiere crear un nuevo tipo sólo por algo que podría ser utilizado en un método.

En el siguiente ejemplo de código, que desea crear un tipo anónimo que contenga sólo la Marca y modelo ya que estas propiedades son las únicas que se necesitan:

--------------------------------------VB------------------------------------------

Dim x = New With {.Make = "VW", .Model = "Bug"}

txtLog.AppendText(x.Make & ", " & x.Model)

--------------------------------------CS------------------------------------------

var x = new {Make = "VW", Model = "Bug"};

txtLog.AppendText(x.Make + ", " + x.Model);

Cuando escribimos la segunda declaración, si despues de x presionamos punto, la ventana de IntelliSense se veran Make y Model como selecciones disponibles. Este es el beneficio de obtener IntelliSense para escenarios en los que las variables locales de tipo implícito se requieren.
Los tipos anónimos se utilizan en LINQ para ofrecer proyecciones. Los tipos anónimos ayudan, como se muestra en este ejemplo:

--------------------------------------VB------------------------------------------

Dim carData = From c In GetCars()

Where c.Year >= 2000

Order By c.Year

Select New With

{

c.VIN,

.MakeAndModel = c.Make + " " + c.Model

}

dgResults.DataSource = carData.ToList()

--------------------------------------CS------------------------------------------

var carData = from c in GetCars()

where c.Year >= 2000

orderby c.Year

select new

{

c.VIN,

MakeAndModel = c.Make + " " + c.Model

};

dgResults.DataSource = carData.ToList();

Cuando este ejemplo se ejecuta la consulta LINQ se localiza todos los coches que tienen un año igual o superior a 2000. Ese resultado se proyecta a un tipo anónimo que agarra elVIN y combina el fabricante y modelo en una nueva propiedad llamada MakeAndModel.Finalmente, el resultado se muestra en la grilla:

clip_image002[4]

Expresiones lambda
Las expresiones lambda se pueden utilizar en cualquier lugar, son muy similares a los métodos anónimos, pero tienen una sintaxis mucho más abreviada que las hace fáciles de usar.
Considere la clase de lista genérica que tiene un método Find. Este método acepta un delegado predicado genérico como parámetro. Este delegado es una referencia a un método que acepta un único parámetro de tipo y devuelve un valor booleano. Ejemplo del uso del método Find con un delegado de predicados:

--------------------------------------VB------------------------------------------

Dim yearToFind As Integer

Private Sub PredecateDelegateToolStripMenuItem_Click( _

ByVal sender As System.Object, _

ByVal e As System.EventArgs) _

Handles PredecateDelegateToolStripMenuItem.Click

yearToFind = 2000

Dim cars = GetCars()

Dim found = cars.Find(AddressOf ByYear)

txtLog.AppendText(String.Format( _

"Car VIN:{0} Make:{1} Year:{2}" & Environment.NewLine, _

found.VIN, found.Make, found.Year))

End Sub

Private Function ByYear(ByVal c As Car) As Boolean

Return c.Year = yearToFind

End Function

--------------------------------------CS------------------------------------------

int yearToFind = 2000;

private void predecateDelegateToolStripMenuItem_Click(

object sender, EventArgs e)

{

var cars = GetCars();

yearToFind = 2000;

var found = cars.Find(ByYear);

txtLog.AppendText(string.Format(

"Car VIN:{0} Make:{1} Year{2}" + Environment.NewLine,

found.VIN, found.Make, found.Year));

}

private bool ByYear(Car c)

{

return c.Year == yearToFind;

}

El ejemplo anterior puede ser reescrito para usar una expresión lambda:

--------------------------------------VB------------------------------------------

Private Sub LambdaExpressionsToolStripMenuItem_Click( _

ByVal sender As System.Object, _

ByVal e As System.EventArgs) _

Handles LambdaExpressionsToolStripMenuItem.Click

Dim cars = GetCars()

Dim theYear = 2000

Dim found = cars.Find(Function(c) c.Year = theYear)

txtLog.AppendText(String.Format( _

"Car VIN:{0} Make:{1} Year:{2}" & Environment.NewLine, _

found.VIN, found.Make, found.Year))

End Sub

--------------------------------------CS------------------------------------------

private void lambdaExpressionsToolStripMenuItem_Click(

object sender, EventArgs e)

{

var cars = GetCars();

var theYear = 2000;

var found = cars.Find(c => c.Year== theYear);

txtLog.AppendText(string.Format(

"Car VIN:{0} Make:{1} Year{2}" + Environment.NewLine,

found.VIN, found.Make, found.Year));

}

Una expresión lambda es como un método de línea. En la parte izquierda se declaran de los parámetros, separados por coma y después del =>, se tiene la expresión. Formalmente, una expresión lambda es una expresión que tiene una entrada y sólo contiene una única instrucción que se evalúa para proporcionar un valor de retorno simple, sin embargo, se pueden pasar varios parámetros y las declaraciones pueden ser múltiples:

--------------------------------------VB------------------------------------------

Dim found = cars.Find(Function(c As Car)

Dim x As Integer

x = theYear

Return c.Year = x

End Function)

--------------------------------------CS------------------------------------------

var found = cars.Find(c =>

{

int x;

x = theYear;

return c.Year == x;

});

En C #, si la expresión lambda tiene varios parámetros, los parámetros deben estar entre paréntesis, y si la expresión lambda no tiene parámetros, debe proporcionar un conjunto vacío de paréntesis donde el parámetro iría.

Métodos de extensión
Los métodos de extensión permiten agregar métodos a un tipo, incluso si no se tiene el código fuente para el tipo.

Ejemplo: se desea añadir un método IsNumeric para la clase de string, pero no no tenemos el código fuente de la clase string. Una solución seria crear una nueva clase que hereda de string, MyString,y se agrega el método IsNumeric para esta clase, pero como la clase String está sellada, lo que significa que no se puede heredar. Otro solución es crear una clase de ayuda,StringHelper, que contenga los métodos para agregar a la clase string.

--------------------------------------VB------------------------------------------

Public Module StringHelper

Public Function IsNumeric(ByVal str As String) As Boolean

Dim val As Double

Return Double.TryParse(str, val)

End Function

End Module

--------------------------------------CS------------------------------------------

public static class StringHelper

{

public static bool IsNumeric(string str)

{

double val;

return double.TryParse(str, out val);

}

}

El siguiente código utiliza la clase StringHelper para poner a prueba un par de strings y ver si son numéricos:

--------------------------------------VB------------------------------------------

Dim s As String = "abc123"

txtLog.AppendText(StringHelper.IsNumeric(s) & Environment.NewLine)

s = "123"

txtLog.AppendText(StringHelper.IsNumeric(s) & Environment.NewLine)

--------------------------------------CS------------------------------------------

string s = "abc123";

txtLog.AppendText(StringHelper.IsNumeric(s) + Environment.NewLine);

s = "123";

txtLog.AppendText(StringHelper.IsNumeric(s) + Environment.NewLine);

En. NET Framework 3.5, Microsoft introdujo los métodos de extensión. Mediante el uso de métodos de extensión, se puede extender un tipo, incluso cuando no se tiene el código fuente para el tipo.
En Visual Basic, se agrega el atributo <Extension()> antes del método.
En C #, se agrega la palabra clave this en frente del primer parámetro para indicar que se está ampliando el tipo de este parámetro.

--------------------------------------VB------------------------------------------

Imports System.Runtime.CompilerServices

Public Module StringHelper

<Extension()> _

Public Function IsNumeric(ByVal str As String) As Boolean

Dim val As Double

Return Double.TryParse(str, val)

End Function

End Module

--------------------------------------CS------------------------------------------

public static class StringHelper

{

public static bool IsNumeric(this string str)

{

double val;

return double.TryParse(str, out val);

}

}

Ahora que el método IsNumeric está en la clase string, y se puede llamar de la siguiente manera:

--------------------------------------VB------------------------------------------

Dim s As String = "abc123"

txtLog.AppendText(s.IsNumeric() & Environment.NewLine)

--------------------------------------CS------------------------------------------

string s = "abc123";

txtLog.AppendText(s.IsNumeric() + Environment.NewLine);

El rendimiento es exactamente el mismo también. La diferencia es que ahora la ventana de IntelliSense muestra los métodos de extensión en todos los strings.

clip_image003[4]

Estas son algunas reglas para trabajar con los métodos de extensión:
■ los métodos de extensión deben ser definidos en un módulo de Visual Basic o C # claseestática.
■ El módulo de Visual Basic o C # clase static debe ser pública.
■ Si se define un método de extensión para un tipo, y el tipo ya tiene el mismo
método, el método tipo es utilizado y el método de extensión se ignora.
■ En C #, la clase y los métodos de extensión debe ser estática. Módulos de Visual Basic y sus métodos son automáticamente static (compartidos Visual Basic).

Métodos de extensión de las consultas

Microsoft ha añadido varios métodos de extensión, pero lo más importante son los métodos que se han añadido a la interfaz IEnumerable genéricos.

Algunos de estos métodos de extensión se asignan directamente a Visual Basic y C # con LINQ (también conocidos como operadores de LINQ).
Para utilizar LINQ y los métodos de extensión de consulta, el proyecto debe hacer referencia a System.Core.dll y, el código, debe importar ( utilizando C # ) el espacio de nombres System.Linq.

La clase Enumerable también tiene tres métodos estáticos que pueden ser útiles:Empty, Range,
y Repeat

■ Empty: produce un objeto genérico IEnumerable sin elementos.
■  Range produce una secuencia números enteros. Este método tiene dos parámetros: el número de inicio y cuántas veces se a a realizar el incremento. Si se pasa 100,5 a este método, se producirá
100, 101, 102, 103, 104.
■ Repeat produce un objeto IEnumerable <int> que tiene el mismo elemento repetido.

La siguiente sección muestra muchos de los métodos de extensión de consulta que se implementan en la clase Enumerable para extender la interfaz IEnumerable.

All:  Devuelve true cuando todos los elementos de la colección cumplen un criterio especificado y devuelve false en caso contrario. Ej: se fija si todos los autos fueron creados después de 1960.

--------------------------------------VB------------------------------------------

txtLog.WriteLine(GetCars().All(Function(c) c.Year > 1960))

--------------------------------------CS------------------------------------------

txtLog.WriteLine(GetCars().All(c => c.Year > 1960));

Any: Devuelve true cuando al menos un elemento de la colección cumple con el criterio especificado y devuelve false en caso contrario. Su uso es similar a ALL.

AsEnumerable:  permite convertir una colección que implementa la interfaz IEnumerable, que está casteada como un tipo diferente, como  por ej: de  IQueryable, a la IEnumerable.
En este ejemplo, una clase llamada MyStringList hereda de la lista de string. Esta clase tiene un
único método Where que sobre escribe el metodo where de la interfase IEnumerable. El método Where de la clase MyStringList devolverá todos los elementos que cumplan con el filtro que se le pase, pero en mayúsculas.

--------------------------------------VB------------------------------------------

Public Class MyStringList

Inherits List(Of String)

Public Function Where(ByVal filter As Predicate(Of String)) As IEnumerable(Of

String)

Return Me.Select(Of String)(Function(s) IIf(filter(s), s.ToUpper(), s))

End Function

End Class

--------------------------------------CS------------------------------------------

public class MyStringList : List<string>

{

public IEnumerable<string> Where(Predicate<string> filter)

{

return this.Select(s=>filter(s) ? s.ToUpper() : s);

}

}

AsQueryable: convierte un objeto IEnumerable a un objeto IQueryable.

En el siguiente ejemplo, el método AsQueryable se ejecuta, y la información está ahora disponible para el proveedor.

--------------------------------------VB------------------------------------------

Private Sub asQueryableToolStripMenuItem_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) _

Handles asQueryableToolStripMenuItem.Click

Dim strings As New MyStringList From {"orange", "apple", "grape", "pear"}

Dim querable = strings.AsQueryable()

txtLog.WriteLine("Element Type:{0}", querable.ElementType)

txtLog.WriteLine("Expression:{0}", querable.Expression)

txtLog.WriteLine("Provider:{0}", querable.Provider)

End Sub

--------------------------------------CS------------------------------------------

private void asQueryableToolStripMenuItem_Click(object sender, EventArgs e)

{

IEnumerable<string> strings = new MyStringList

{ "orange", "apple", "grape", "pear" };

var querable = strings.AsQueryable();

txtLog.WriteLine("Element Type:{0}", querable.ElementType);

txtLog.WriteLine("Expression:{0}", querable.Expression);

txtLog.WriteLine("Provider:{0}", querable.Provider);

}

Average: método que puede calcular un promedio de una propiedad numérica que existe en los elementos de su colección.

--------------------------------------VB------------------------------------------

Dim averageYear = GetCars().Average(Function(c) c.Year)

txtLog.WriteLine(averageYear)

--------------------------------------CS------------------------------------------

var averageYear = GetCars().Average(c => c.Year);

txtLog.WriteLine(averageYear);

Cast: cuando se quiere convertir cada uno de los elementos a un tipo diferente. Cast no es un filtro, si se quieren recuperar todos los elementos de un tipo específico, se usa OfType.:

--------------------------------------VB------------------------------------------

Private Sub castToolStripMenuItem_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles castToolStripMenuItem.Click

Dim cars As IEnumerable(Of Car) = GetCars()

Dim objects As IEnumerable(Of Object) = cars.Cast(Of Object)()

End Sub

--------------------------------------CS------------------------------------------

private void castToolStripMenuItem_Click(object sender, EventArgs e)

{

IEnumerable<Car> cars = GetCars();

IEnumerable<Object> objects = cars.Cast<object>();

}

Concat: para combinar dos secuencias. Es similar al operador de la Union, pero Unión elimina los duplicados, Concat no:

--------------------------------------VB------------------------------------------

Private Sub concatToolStripMenuItem_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) _

Handles concatToolStripMenuItem.Click

Dim lastYearScores As Integer() = New Integer() {88, 56, 23, 99, 65}

Dim thisYearScores As Integer() = New Integer() {93, 78, 23, 99, 90}

Dim item As Integer

For Each item In lastYearScores.Concat(thisYearScores)

Me.txtLog.WriteLine(item)

Next

End Sub

--------------------------------------CS------------------------------------------

private void concatToolStripMenuItem_Click(object sender, EventArgs e)

{

int[] lastYearScores = { 88, 56, 23, 99, 65 };

int[] thisYearScores = { 93, 78, 23, 99, 90 };

foreach (var item in lastYearScores.Concat(thisYearScores))

{

txtLog.WriteLine(item);

}

}

El resultado seria:

88
56
23
99
65
93
78
23
99
90

Contains: Determina si un elemento existe en el origen.

--------------------------------------VB------------------------------------------

Dim cars = Me.GetCars

Dim c1 = cars.Item(2)

Dim c2 As New Car

txtLog.WriteLine(cars.Contains(c1))

txtLog.WriteLine(cars.Contains(c2))

--------------------------------------CS------------------------------------------

var cars = GetCars();

Car c1 = cars[2];

Car c2 = new Car();

txtLog.WriteLine(cars.Contains(c1));

txtLog.WriteLine(cars.Contains(c2));

 

Count: devuelve el recuento de los elementos que contiene.

--------------------------------------VB------------------------------------------

Dim cars = Me.GetCars

txtLog.WriteLine(cars.Count())

--------------------------------------CS------------------------------------------

var cars = GetCars();

txtLog.WriteLine(cars.Count());

DefaultIfEmpty: se usa cuando se sospecha que la colección de origen podría no tener ningún elemento, pero se quiere que al menos exista un elemento con un valor predeterminado del tipo (falso para Boolean, 0 para numérico, y nulo para un tipo de referencia).

--------------------------------------VB------------------------------------------

Dim cars As New List(Of Car)

Dim oneNullCar = cars.DefaultIfEmpty()

For Each car In oneNullCar

txtLog.WriteLine(IIf((car Is Nothing), "Null Car", "Not Null Car"))

Next

--------------------------------------CS------------------------------------------

List<Car> cars = new List<Car>();

IEnumerable<Car> oneNullCar = cars.DefaultIfEmpty();

foreach (var car in oneNullCar)

{

txtLog.WriteLine(car == null ? "Null Car" : "Not Null Car");

}

El resultado seria Null Car, ya que se le paso un objeto vacío (Car).

 

No hay comentarios:

Publicar un comentario