Làm thế nào để lặp qua tất cả các thuộc tính của một lớp?


168

Tôi có một lớp học.

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

Tôi muốn lặp qua các thuộc tính của lớp trên. ví dụ;

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

Câu trả lời:


297

Sử dụng phản xạ:

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

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

cho Excel - những công cụ / mục tham chiếu nào phải được thêm vào để có quyền truy cập vào BindingFlags, vì không có mục "System.Reflection" trong danh sách

Chỉnh sửa: Bạn cũng có thể chỉ định giá trị BindingFlags cho type.GetProperties():

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

Điều đó sẽ hạn chế các thuộc tính được trả về đối với các thuộc tính công khai (không bao gồm các thuộc tính tĩnh, thuộc tính được bảo vệ, v.v.).

Bạn không cần chỉ định BindingFlags.GetProperty, bạn sử dụng điều đó khi gọi type.InvokeMember()để nhận giá trị của tài sản.


Btw, không nên có một số cờ ràng buộc cho phương thức GetProperIES đó? Thích BindingFlags.Public | BindingFlags.GetPropertyhay sao?
Svish

@Svish, bạn nói đúng :) Nó có thể sử dụng một số BindingFlags, nhưng chúng là tùy chọn. Bạn có thể muốn công khai | Sơ thẩm.
Brannon

Mẹo: Nếu bạn đang xử lý các trường tĩnh, thì chỉ cần chuyển null ở đây: property.GetValue (null);
alansiqueira27

42

Lưu ý rằng nếu đối tượng bạn đang nói đến có mô hình thuộc tính tùy chỉnh (chẳng hạn như DataRowViewvv DataTable), thì bạn cần sử dụng TypeDescriptor; tin tốt là điều này vẫn hoạt động tốt đối với các lớp thông thường (và thậm chí có thể nhanh hơn nhiều so với phản xạ ):

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

Điều này cũng cung cấp quyền truy cập dễ dàng vào những thứ như TypeConverterđịnh dạng:

    string fmt = prop.Converter.ConvertToString(prop.GetValue(obj));

32

Phiên bản VB của C # được cung cấp bởi 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

Sử dụng cờ Binding thay cho dòng số 3

    Dim flags As BindingFlags = BindingFlags.Public Or BindingFlags.Instance
    Dim properties() As PropertyInfo = _type.GetProperties(flags)

Cảm ơn, tôi sẽ mất quá nhiều thời gian để chuyển đổi sang VB :)
Brannon

bạn luôn có thể sử dụng trình chuyển đổi tự động, có rất nhiều trên web :)
balexandre

1
Có nhưng không tốt bằng mã hóa tay. Một trong những điều đáng chú ý là công cụ chuyển đổi mã telerik
Sachin Chavan

Dưới đây là cách Telerik đã chuyển đổi: gist.github.com/shmup/3f5abd617a525416fee7
shmup 22/2/2016

7

Phản xạ là khá "nặng"

Có lẽ thử giải pháp này: // 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

Sự phản xạ chậm lại +/- 1000 x tốc độ của một cuộc gọi phương thức, được hiển thị trong Hiệu suất của mọi thứ hàng ngày


2

Đây là một cách khác để làm điều đó, sử dụng lambda LINQ:

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)}"))

1

Đây là cách tôi làm điều đó.

foreach (var fi in typeof(CustomRoles).GetFields())
{
    var propertyName = fi.Name;
}

1
Sử dụng GetProperIES () thay vì GetFields () nếu đối tượng / lớp chứa các thuộc tính thay vì các trường.
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);
        }
    }

Tôi đã sử dụng khối mã ở trên để đặt lại tất cả các thuộc tính chuỗi trong đối tượng điều khiển người dùng web của mình, tên được bắt đầu bằng "Doc".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.