¿Cómo recorrer todas las propiedades de una clase?

168

Tengo una clase.

Public Class Foo
    Private _Name As String
    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Private _Age As String
    Public Property Age() As String
        Get
            Return _Age
        End Get
        Set(ByVal value As String)
            _Age = value
        End Set
    End Property

    Private _ContactNumber As String
    Public Property ContactNumber() As String
        Get
            Return _ContactNumber
        End Get
        Set(ByVal value As String)
            _ContactNumber = value
        End Set
    End Property


End Class

Quiero recorrer las propiedades de la clase anterior. p.ej;

Public Sub DisplayAll(ByVal Someobject As Foo)
    For Each _Property As something In Someobject.Properties
        Console.WriteLine(_Property.Name & "=" & _Property.value)
    Next
End Sub
Sachin Chavan
fuente

Respuestas:

297

Use Reflexión:

Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();

foreach (PropertyInfo property in properties)
{
    Console.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(obj, null));
}

para Excel: qué herramientas / elemento de referencia se deben agregar para obtener acceso a BindingFlags, ya que no hay una entrada "System.Reflection" en la lista

Editar: También puede especificar un valor de BindingFlags para type.GetProperties():

BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
PropertyInfo[] properties = type.GetProperties(flags);

Eso restringirá las propiedades devueltas a propiedades de instancia pública (excluyendo propiedades estáticas, propiedades protegidas, etc.).

No necesita especificar BindingFlags.GetProperty, lo usa cuando llama type.InvokeMember()para obtener el valor de una propiedad.

Brannon
fuente
Por cierto, ¿no debería haber algunas banderas de enlace para ese método GetProperties? ¿Me gusta BindingFlags.Public | BindingFlags.GetPropertyo algo?
Svish
@Svish, tienes razón :) Podría usar algunos BindingFlags, pero son opcionales. Probablemente quieras Public | Ejemplo.
Brannon
Consejo: Si está tratando con campos estáticos, simplemente pase nulo aquí: propiedad.GetValue (nulo);
alansiqueira27
42

Tenga en cuenta que si el objeto del que está hablando tiene un modelo de propiedad personalizado (como DataRowViewetc para DataTable), entonces debe usarlo TypeDescriptor; La buena noticia es que esto todavía funciona bien para las clases regulares (e incluso puede ser mucho más rápido que la reflexión ):

foreach(PropertyDescriptor prop in TypeDescriptor.GetProperties(obj)) {
    Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(obj));
}

Esto también proporciona un fácil acceso a cosas como el TypeConverterformato:

    string fmt = prop.Converter.ConvertToString(prop.GetValue(obj));
Marc Gravell
fuente
32

Versión VB de C # dada por Brannon:

Public Sub DisplayAll(ByVal Someobject As Foo)
    Dim _type As Type = Someobject.GetType()
    Dim properties() As PropertyInfo = _type.GetProperties()  'line 3
    For Each _property As PropertyInfo In properties
        Console.WriteLine("Name: " + _property.Name + ", Value: " + _property.GetValue(Someobject, Nothing))
    Next
End Sub

Usar banderas de enlace en lugar de la línea no.3

    Dim flags As BindingFlags = BindingFlags.Public Or BindingFlags.Instance
    Dim properties() As PropertyInfo = _type.GetProperties(flags)
Sachin Chavan
fuente
Gracias, me hubiera llevado demasiado tiempo convertirme a VB :)
Brannon
siempre se puede utilizar un convertidor automático, hay muchos en la web :)
balexandre
1
Sí, pero no todo es tan bueno como la codificación manual. Uno notable es el convertidor de código telerik
Sachin Chavan
Así es como Telerik se habría convertido: gist.github.com/shmup/3f5abd617a525416fee7
shmup
7

La reflexión es bastante "pesada"

Quizás pruebe esta solución: // C #

if (item is IEnumerable) {
    foreach (object o in item as IEnumerable) {
            //do function
    }
} else {
    foreach (System.Reflection.PropertyInfo p in obj.GetType().GetProperties())      {
        if (p.CanRead) {
            Console.WriteLine("{0}: {1}", p.Name, p.GetValue(obj,  null)); //possible function
        }
    }
}

'VB.Net

  If TypeOf item Is IEnumerable Then

    For Each o As Object In TryCast(item, IEnumerable)
               'Do Function
     Next
  Else
    For Each p As System.Reflection.PropertyInfo In obj.GetType().GetProperties()
         If p.CanRead Then
               Console.WriteLine("{0}: {1}", p.Name, p.GetValue(obj, Nothing))  'possible function
          End If
      Next
  End If

La reflexión se ralentiza +/- 1000 x la velocidad de una llamada al método, que se muestra en The Performance of Everyday Things

NicoJuicy
fuente
2

Aquí hay otra forma de hacerlo, usando un LINQ lambda:

C#:

SomeObject.GetType().GetProperties().ToList().ForEach(x => Console.WriteLine($"{x.Name} = {x.GetValue(SomeObject, null)}"));

VB.NET:

SomeObject.GetType.GetProperties.ToList.ForEach(Sub(x) Console.WriteLine($"{x.Name} = {x.GetValue(SomeObject, Nothing)}"))
01F0
fuente
1

Así es como lo hago.

foreach (var fi in typeof(CustomRoles).GetFields())
{
    var propertyName = fi.Name;
}
Chris Go
fuente
1
Use GetProperties () en lugar de GetFields () si el objeto / clase contiene propiedades en lugar de campos.
GarDavis
0
private void ResetAllProperties()
    {
        Type type = this.GetType();
        PropertyInfo[] properties = (from c in type.GetProperties()
                                     where c.Name.StartsWith("Doc")
                                     select c).ToArray();
        foreach (PropertyInfo item in properties)
        {
            if (item.PropertyType.FullName == "System.String")
                item.SetValue(this, "", null);
        }
    }

Utilicé el bloque de código anterior para restablecer todas las propiedades de cadena en mi objeto de control de usuario web cuyos nombres comienzan con "Doc".

Jack
fuente