Donde nos ponemos a investigar un poco que tienen nuestros objetos.
Donde nos ponemos a investigar un poco que tienen nuestros objetos.
Motivación.
Para muchas de las cosas que venimos explicando, acerca de generalizaciones de código, métodos compartidos y demás, cuando programemos, seguramente querremos interactuar con dichas generalizaciones, pero de un modo más específico.
Por ejemplo, en la anterior publicación, hablábamos de Atributos.
¿Cómo hago para saber si una propiedad tiene determinado atributo?
¿Cómo obtengo los miembros que tienen cierto atributo?
El espacio de nombres System.Reflection.
El .Net Framework implementa este espacio de nombres específico, para poder investigar los objetos.
Con él, a partir del Type de un objeto, se puede obtener información de sus miembros, sus atributos, su jerarquía de herencia etc.
El espacio expone objetos que sirven como descriptores de las características de un tipo, como, por Ejemplo:
- Assembly
- MemberInfo
- PropertyInfo
Dichos objetos se obtienen, como fue dicho, del Type de un objeto o instancia utilizando el método GetType()
Obtener el tipo
Existen distintos métodos para obtener el tipo, dependiendo si se tiene o no una instancia del mismos.
Los métodos, todos retornando un objeto Type, se describen en el siguiente cuadro
|
C# |
VB |
Con Instancia |
variable.GetType() |
variable.GetType |
Sin Instancia |
typeof(Nombre_De_Clase) |
GetType(Nombre_de_Clase) |
Funciones.
En muchos casos, utilizaremos LinQ sobre objetos para obtener información (lo cual facilita la codificación y acelera el proceso).
Comprobar Propiedades.
Comprobar si tiene un atributo
private static bool HasAttribute(PropertyInfo p, string attributeName)
{
var attrs = p.GetCustomAttributesData();
if (attrs.Count > 0)
{
var attrs2 = (from aa in attrs where aa.AttributeType.Name == attributeName select aa).ToList();
return attrs2.Count > 0;
}
return false;
}
Private Shared Function HasAttribute(p As PropertyInfo, attributeFullName As String) As Boolean
Dim attrs = p.GetCustomAttributesData
If attrs.Count > 0 Then
Dim attrs2 = (From aa In attrs Where aa.AttributeType.Name = attributeFullName).ToList
Return attrs2.Count > 0
End If
Return False
End Function
Como se ve, se aplica sobre un objeto PropertyInfo y filtra directamente por nombre.
Obtener los atributos de una propiedad
public static NameValueList GetAttributes(PropertyInfo property)
{
NameValueList result = new NameValueList();
var v = property.GetCustomAttributesData();
foreach (var a_loopVariable in v)
{
var a = a_loopVariable;
foreach (var named_loopVariable in a.NamedArguments)
{
var named = named_loopVariable;
NameValue<object> nv = new NameValue<object>(named.MemberName) { RawValue = named.TypedValue.Value };
result.Add(nv);
}
}
return result;
}
Public Shared Function GetAttributes(ByVal [property] As PropertyInfo) As DSCommon.NameValueList
Dim result As New DSCommon.NameValueList
Dim v = [property].GetCustomAttributesData()
For Each a In v
For Each named In a.NamedArguments
Dim nv As New DSCommon.NameValue(Of Object)(named.MemberName) With {.RawValue = named.TypedValue.Value}
result.Add(nv)
Next
Next
Return result
End Function
En este caso, la función retorna todos los atributos asignados a un PropertyInfo (o sea, a una propiedad), y retorna nuestro NameValueList con los valores obtenidos.
Obtener miembros específicos por atributo de un tipo
Obtener las propiedades que poseen un determinado atributo.
public static List<PropertyInfo> GetPropertiesByAttribute(Type type, Attribute attribute)
{
string s = attribute.GetType().ToString();
var v = (from p in type.GetProperties() where (from aa in p.GetCustomAttributes(true) where aa.ToString() == s select aa).Count() > 0 select p);
List<PropertyInfo> l = new List<PropertyInfo>();
l.AddRange(v);
return l;
}
Public Shared Function GetPropertiesByAttribute(ByVal type As Type, ByVal attribute As Attribute) As List(Of PropertyInfo) Dim s As String = attribute.GetType.ToString
Dim v = (From p As PropertyInfo In type.GetProperties
Where (From aa In p.GetCustomAttributes(True) Where aa.ToString = s).Count > 0)
Dim l As New List(Of PropertyInfo)
l.AddRange(v)
Return l
End Function
En este caso, la función se aplica sobre un tipo, del cual se obtienen las propiedades. De ellas, aquellas que tengan asignado un determinado atributo.
Obtener miembros específicos por nombre del atributo de un tipo
public static List<PropertyInfo> GetPropertiesByAttribute(
Type type, string attributeFullName)
var v = (from p in type.GetProperties() where (HasAttribute(p, attributeFullName)) select p);
List<PropertyInfo> l = new List<PropertyInfo>(); l.AddRange(v);
return l;
}
Public Shared Function GetPropertiesByAttribute(ByVal type As Type, ByVal attributeFullName As String) As List(Of PropertyInfo)
Dim v = (From p As PropertyInfo In type.GetProperties
Where (HasAttribute(p, attributeFullName)))
Dim l As New List(Of PropertyInfo)
l.AddRange(v)
Return l
End Function
En este caso, en lugar de utilizar el atributo propiamente dicho, se utiliza su nombre.
Comprobar clases.
Obtener los nombres de las clases que heredan de otra (o implementan una interfaz)
public static string[] GetClasesOfType<T>(System.Reflection.Assembly assembly)
{
Type theI = typeof(T);
var elems = (from el in assembly.GetTypes() where theI.IsAssignableFrom(el) select el.Name).ToArray();
return elems;
}
Public Shared Function GetClasesOfType(Of T)(assembly As System.Reflection.Assembly) As String()
Dim theI As Type = GetType(T)
Dim elems = (From el In assembly.GetTypes() Where theI.IsAssignableFrom(el) Select el.Name).ToArray()
Return elems
End Function
Terminamos teniendo una nueva herramienta
Agregaremos entonces una clase a nuestra biblioteca de herramientas (Tools), que podríamos llamar, precisamente, Reflection, para exponer estos métodos.
Nótese que todos están declarados como static (Shared en VB), para poder utilizarlas sin necesitar crear una instancia de la clase.
En la próxima entrega, repasaremos el espacio de nombre Tools y lo complementaremos con más cositas
Un comentario en “Reflection”