Jak przeglądać wszystkie właściwości klasy?

168

Mam klasę.

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

Chcę przejrzeć właściwości powyższej klasy. na przykład;

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
źródło

Odpowiedzi:

297

Użyj odbicia:

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

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

dla programu Excel - jakie narzędzia / element referencyjny należy dodać, aby uzyskać dostęp do BindingFlags, ponieważ na liście nie ma wpisu „System.Reflection”

Edycja: możesz również określić wartość BindingFlags, aby type.GetProperties():

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

Spowoduje to ograniczenie zwracanych właściwości do właściwości wystąpienia publicznego (z wyłączeniem właściwości statycznych, właściwości chronionych itp.).

Nie musisz określać BindingFlags.GetProperty, używasz tego podczas wywoływania, type.InvokeMember()aby uzyskać wartość właściwości.

Brannon
źródło
Przy okazji, czy nie powinno być kilku flag wiążących dla tej metody GetProperties? Jak BindingFlags.Public | BindingFlags.GetPropertyczy coś?
Svish
@Svish, masz rację :) Przydałoby się kilka BindingFlags, ale są one opcjonalne. Prawdopodobnie chcesz Public | Instancja.
Brannon
Wskazówka: jeśli masz do czynienia z polami statycznymi, po prostu podaj tutaj wartość null: property.GetValue (null);
alansiqueira27
42

Zwróć uwagę, że jeśli obiekt, o którym mówisz, ma model właściwości niestandardowych (na przykład DataRowViewitp. DataTable), Musisz użyć TypeDescriptor; dobrą wiadomością jest to, że to nadal działa dobrze na zwykłych zajęciach (i może być nawet znacznie szybsze niż refleksja ):

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

Zapewnia to również łatwy dostęp do rzeczy, takich jak TypeConverterformatowanie:

    string fmt = prop.Converter.ConvertToString(prop.GetValue(obj));
Marc Gravell
źródło
32

Wersja języka VB C # podana przez Brannona:

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

Używanie flag Binding zamiast linii nr 3

    Dim flags As BindingFlags = BindingFlags.Public Or BindingFlags.Instance
    Dim properties() As PropertyInfo = _type.GetProperties(flags)
Sachin Chavan
źródło
Dzięki, przejście na VB zajęłoby mi zbyt dużo czasu :)
Brannon,
zawsze możesz skorzystać z automatycznego konwertera, w sieci jest mnóstwo :)
balexandre
1
Tak, ale nie wszystko tak dobre, jak kodowanie ręczne. Godnym uwagi jest konwerter kodów telerik
Sachin Chavan
Oto, jak Telerik by się przekonwertował: gist.github.com/shmup/3f5abd617a525416fee7
shmup
7

Odbicie jest dość „ciężkie”

Być może wypróbuj to rozwiązanie: // 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

Odbicie spowalnia +/- 1000-krotność szybkości wywołania metody, pokazanej w The Performance of Everyday Things

NicoJuicy
źródło
2

Oto inny sposób, aby to zrobić, używając LINQ lambda:

DO#:

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
źródło
1

Tak to robię.

foreach (var fi in typeof(CustomRoles).GetFields())
{
    var propertyName = fi.Name;
}
Chris Go
źródło
1
Użyj GetProperties () zamiast GetFields (), jeśli obiekt / klasa zawiera właściwości zamiast pól.
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);
        }
    }

Użyłem powyższego bloku kodu, aby zresetować wszystkie właściwości ciągu w moim obiekcie kontroli użytkownika, którego nazwy są rozpoczynane od „Doc”.

Jacek
źródło