Ago 14 2008
Como filtrar una lista de objetos con LINQ y ver las propiedades por Reflection (VB.Net) {
En el sitio de Microsoft hay una traducción de la página del proyecto LINQ donde se puede leer más al respecto.
En nuestro ejemplo utilizaremos LINQ To Objects, que es el término que se utiliza para definir la utilización de LINQ con cualquier colección que implemente las interfaces IEnumerable o IEnumerable(T).
En nuestro caso hemos definido una clase Objeto que tiene las propiedades ID : Integer, Tipo : String, Tamaño : Decimal y Habilitado : Boolean. Para utilizar LINQ hemos creado una colección del tipo List(Of Objeto) la cual cargamos con varias instancias de nuestra clase Objeto.
La idea es crear un filtro dinámico, para dar la posibilidad al usuario de seleccionar el valor para 2 propiedades y crear un filtro con OR o AND, o sea Propiedad1 = a OR/AND Propiedad2 = b.
Nuestra intención es poder reutilizar el código, entonces no podemos crear 2 ComboBox y cargar las propiedades a mano, por lo que recurriremos al namespace System.Reflection para extraer las propiedades de nuestra clase Objeto.
Según Microsoft: El espacio de nombres System.Reflection contiene clases e interfaces que proporcionan una vista administrada de los campos, los métodos y los tipos cargados, con la posibilidad de crear e invocar tipos dinámicamente.
Private Sub CargarPropiedades() Dim propiedades1 As New List(Of String) Dim propiedades2 As New List(Of String) ' Recorremos todos los miembros de la clase For Each propiedad As System.Reflection.MemberInfo In System.Reflection.Assembly.GetExecutingAssembly.GetType("Objeto").GetMembers() ' Filtramos para seleccionar solamente las propiedades If propiedad.MemberType = System.Reflection.MemberTypes.Property Then propiedades1.Add(propiedad.Name) propiedades2.Add(propiedad.Name) End If Next Me.cmbField1.DataSource = propiedades1 'Asignamos el DataSource a nuestros ComboBox Me.cmbField2.DataSource = propiedades2 End Sub
Con ese código tan simple ya tenemos 2 combos cargados con las propiedades de nuestra clase Objeto. En este caso ob tuvimos el tipo Objeto del mismo ensamblado, (Assembly), en el que estamos trabajando, pero pudimos haberlo buscado en otro Assembly.
Cabe aclarar que se utilizan 2 listas, una para cada combo porque si seteamos la misma lista como DataSource para los 2 ComboBox, al cambiar el valor seleccionado en uno, se cambia también en el otro.
Sólo resta armar nuestra sentencia LINQ para filtrar la coleeción de Objeto. Para ello tenemos que tomar: 1) la primera propiedad seleccionada por el usuario, 2) el valor que ingresó para esa propiedad, 3) la condición que seleccionó (AND/OR), 4) la segunda propiedad seleccionada, 5) el valor ingresado para la segunda propiedad.
Lo que haremos será armar la sentencia de la siguiente manera:
- Seleccionar todos los objetos con PropiedadSeleccionada1 = ValorIngresado1
- AND Si el usuario seleccionó ‘AND’ PropiedadSeleccionada2 = ValorIngresado2, sino True
- OR Si el usuario seleccionó ‘OR’ PropiedadSeleccionada2 = ValorIngresado2 sino False.
Entonces la sentencia, en pseudo-código se vería de una se las siguientes maneras:
- Seleccionar todos los objetos con Propiedad1 = Valor1 AND Propiedad2 = Valor2 OR False
- Seleccionar todos los objetos con Propiedad1 = Valor2 AND True OR Propiedad2 = Valor2
De esa manera con una misma sentencia se cubren los 2 casos, veamos el código:
Private Sub btnSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelect.Click If ValidarEntrada() Then ' Chequeaar que el usuario haya ingresado todos los valores necesarios Try ' LINQ To Objects Dim resSelect = From obj In mObjetos _ Select obj _ Where obj.GetType().GetProperty(Me.cmbField1.SelectedItem.ToString()).GetValue(obj, Nothing) = Me.txtCond1.Text _ And (IIf(cmbJoin.SelectedItem = "AND", obj.GetType().GetProperty(Me.cmbField2.SelectedItem.ToString()).GetValue(obj, Nothing) = Me.txtCond2.Text, True)) _ Or (IIf(cmbJoin.SelectedItem = "OR", obj.GetType().GetProperty(Me.cmbField2.SelectedItem.ToString()).GetValue(obj, Nothing) = Me.txtCond2.Text, False)) Me.lstSelect.Items.Clear() ' Limpiar la lista antes de mostrar el resultado de la consulta For Each item In resSelect Me.lstSelect.Items.Add(item) Next Catch ex As Exception If MessageBox.Show(String.Format("Error: {0}{1}Desea ver más información acerca de este error?", ex.Message.ToString(), Environment.NewLine), "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) = Windows.Forms.DialogResult.Yes Then MessageBox.Show(ex.ToString(), "Detalle del error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) End If End Try End If End Sub
Descargar el ejemplo de LINQ y reflection (42.24 KB)
}