c # foreach (thuộc tính trong đối tượng)… Có cách nào đơn giản để làm điều này không?


92

Tôi có một lớp chứa một số thuộc tính (tất cả đều là chuỗi nếu nó tạo ra bất kỳ sự khác biệt nào).
Tôi cũng có một danh sách, chứa nhiều trường hợp khác nhau của lớp.

Trong khi tạo một số bài kiểm tra đơn vị cho các lớp của mình, tôi quyết định muốn lặp qua từng đối tượng trong danh sách và sau đó lặp qua từng thuộc tính của đối tượng đó ...

Tôi nghĩ làm điều này sẽ đơn giản như ...

foreach (Object obj in theList)
{
     foreach (Property theProperties in obj)
     {
         do some stufff!!;
     }
}

Nhưng điều này đã không hoạt động! :( Tôi gặp lỗi này ...

"câu lệnh foreach không thể hoạt động trên các biến kiểu 'Application.Object' vì 'Application.Object' không chứa định nghĩa công khai cho 'GetEnumerator'"

Có ai biết cách thực hiện điều này mà không cần đến hàng tấn ifs và vòng lặp hoặc không gặp phải bất cứ điều gì quá phức tạp không?


5
Trong tương lai, vui lòng không nói "Nó không hoạt động" trong một câu hỏi. Thay vào đó, hãy chỉ định vấn đề bạn đang gặp phải (lỗi trình biên dịch, v.v.). Cảm ơn!
Robert Harvey

2
Đã cập nhật! Cảm ơn Thủ trưởng lên Robert
Jammerz858

Câu trả lời:


143

Hãy thử cái này:

foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
{
   // do stuff here
}

Cũng xin lưu ý rằng Type.GetProperties()có một quá tải chấp nhận một tập hợp các cờ liên kết để bạn có thể lọc ra các thuộc tính trên một tiêu chí khác như mức trợ năng, hãy xem MSDN để biết thêm chi tiết: Phương pháp Type.GetProperties (BindingFlags) Cuối cùng nhưng không kém phần quan trọng, đừng quên thêm tham chiếu lắp ráp "system.Reflection".

Ví dụ để giải quyết tất cả các thuộc tính công cộng:

foreach (var propertyInfo in obj.GetType()
                                .GetProperties(
                                        BindingFlags.Public 
                                        | BindingFlags.Instance))
{
   // do stuff here
}

Vui lòng cho tôi biết liệu điều này có hoạt động như mong đợi hay không.


4
Một khi bạn đã xử lý các thuộc tính đối tượng, liệu có cách nào lấy giá trị của từng thuộc tính không? tức là một Tên hoặc Mã bưu ví dụ
JsonStatham

36

Bạn có thể lặp qua tất cả các thuộc tính không được lập chỉ mục của một đối tượng như sau:

var s = new MyObject();
foreach (var p in s.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) {
    Console.WriteLine(p.GetValue(s, null));
}

GetProperties()trả về các chỉ mục cũng như các thuộc tính đơn giản, bạn cần một bộ lọc bổ sung trước khi gọi GetValueđể biết rằng việc chuyển nulllàm tham số thứ hai là an toàn .

Bạn có thể cần phải sửa đổi thêm bộ lọc để loại bỏ các thuộc tính chỉ ghi và không thể truy cập.


+1 để chỉ làm điều gì đó với các thuộc tính thực sự có thể được sử dụng - bạn cũng có thể muốn lọc ra các thuộc tính chỉ ghi.

@hvd Đó là một điểm tuyệt vời về thuộc tính chỉ ghi! Tôi gần như đã quên về chúng. Mã của tôi sẽ bị lỗi nếu nó gặp thuộc tính với nullgetter, nhưng tôi chắc chắn OP sẽ tìm ra cách chỉ lấy các thuộc tính mà anh ta cần.
Sergey Kalinichenko

27

Của bạn gần như ở đó, bạn chỉ cần lấy các thuộc tính từ loại, thay vì mong đợi các thuộc tính có thể truy cập được dưới dạng một bộ sưu tập hoặc túi tài sản:

var property in obj.GetType().GetProperties()

Từ đó bạn có thể truy cập như vậy :

property.Name
property.GetValue(obj, null)

Với GetValuetham số thứ hai sẽ cho phép bạn chỉ định các giá trị chỉ mục, sẽ hoạt động với các thuộc tính trả về các tập hợp - vì một chuỗi là một tập hợp các ký tự, bạn cũng có thể chỉ định một chỉ mục để trả về một ký tự nếu cần.


1
Tôi có làm ai đó buồn không? Tôi cởi mở để biết điều gì sai về điều này, nếu không tôi có thể không bao giờ học được.
Grant Thomas

Bạn có thể nhận được phiếu tán thành khi mã của bạn sai (trước khi ninja của bạn chỉnh sửa).
Robert Harvey

20

Chắc chắn không có vấn đề:

foreach(object item in sequence)
{
    if (item == null) continue;
    foreach(PropertyInfo property in item.GetType().GetProperties())
    {
        // do something with the property
    }
}

tại sao bạn lại thêm dòng này? if (item == null) continue;cá nhân, tôi nghĩ nếu bạn nhận được một đối tượng null tại thời điểm đó, đã xảy ra lỗi rất nhiều trước đó và đó là nơi xác thực nên được, hay tôi đã sai?
Rafael Herscovici

@Dementic: Chắc chắn, chúng ta có thể nói rằng trình tự bắt buộc phải chứa các tham chiếu không rỗng.
Eric Lippert

3

Sử dụng Phản chiếu để làm điều này

SomeClass A = SomeClass(...)
PropertyInfo[] properties = A.GetType().GetProperties();

2

Tôi đã tìm câu trả lời cho một câu hỏi tương tự trên trang này, tôi đã viết câu trả lời cho một số câu hỏi tương tự có thể giúp ích cho những người vào trang này.

Danh sách lớp học

Lớp List <T> đại diện cho danh sách các đối tượng có thể được truy cập bằng chỉ mục. Nó nằm trong không gian tên System.Collection.Generic. Lớp danh sách có thể được sử dụng để tạo một tập hợp các kiểu khác nhau như số nguyên, chuỗi, v.v. Lớp danh sách cũng cung cấp các phương thức để tìm kiếm, sắp xếp và thao tác với danh sách.

Lớp với tài sản :

class TestClss
{
    public string id { set; get; }
    public string cell1 { set; get; }
    public string cell2 { set; get; }
}
var MyArray = new List<TestClss> {
    new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (PropertyInfo property in Item.GetType().GetProperties())
    {
        var Key = property.Name;
        var Value = property.GetValue(Item, null);
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

HOẶC, Lớp với trường :

class TestClss
{
    public string id = "";
    public string cell1 = "";
    public string cell2 = "";
}
var MyArray = new List<TestClss> {
    new TestClss() { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new TestClss() { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new TestClss() { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var fieldInfo in Item.GetType().GetFields())
    {
        var Key = fieldInfo.Name;
        var Value = fieldInfo.GetValue(Item);
    }

}

HOẶC, Danh sách các đối tượng (không có các ô giống nhau):

var MyArray = new List<object> {
    new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data", anotherCell = "" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var props in Item.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(Item, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

HOẶC, Danh sách các đối tượng (Nó phải có các ô giống nhau):

var MyArray = new[] {
    new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
foreach (object Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (var props in Item.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(Item, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

HOẶC, Danh sách các đối tượng (có khóa):

var MyArray = new {
    row1 = new { id = "1", cell1 = "cell 1 row 1 Data", cell2 = "cell 2 row 1 Data" },
    row2 = new { id = "2", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 2 Data" },
    row3 = new { id = "3", cell1 = "cell 1 row 2 Data", cell2 = "cell 2 row 3 Data" }
};
// using System.ComponentModel;  for TypeDescriptor
foreach (PropertyDescriptor Item in TypeDescriptor.GetProperties(MyArray))
{
    string Rowkey = Item.Name;
    object RowValue = Item.GetValue(MyArray);
    Console.WriteLine("Row key is: {0}", Rowkey);
    foreach (var props in RowValue.GetType().GetProperties())
    {
        var Key = props.Name;
        var Value = props.GetMethod.Invoke(RowValue, null).ToString();
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

HOẶC, Danh sách Từ điển

var MyArray = new List<Dictionary<string, string>>() {
    new Dictionary<string, string>() { { "id", "1" }, { "cell1", "cell 1 row 1 Data" }, { "cell2", "cell 2 row 1 Data" } },
    new Dictionary<string, string>() { { "id", "2" }, { "cell1", "cell 1 row 2 Data" }, { "cell2", "cell 2 row 2 Data" } },
    new Dictionary<string, string>() { { "id", "3" }, { "cell1", "cell 1 row 3 Data" }, { "cell2", "cell 2 row 3 Data" } }
};
foreach (Dictionary<string, string> Item in MyArray)
{
    Console.WriteLine("Row Start");
    foreach (KeyValuePair<string, string> props in Item)
    {
        var Key = props.Key;
        var Value = props.Value;
        Console.WriteLine("{0}={1}", Key, Value);
    }
}

Chúc may mắn..


0

Một lời cảnh báo nhỏ, nếu "thực hiện một số nội dung" có nghĩa là cập nhật giá trị của thuộc tính thực tế mà bạn truy cập VÀ nếu có thuộc tính kiểu struct dọc theo đường dẫn từ đối tượng gốc đến thuộc tính đã truy cập, thì thay đổi bạn đã thực hiện trên thuộc tính sẽ không được phản ánh trên đối tượng gốc.


0

Giải pháp sao chép-dán (các phương pháp mở rộng) chủ yếu dựa trên các câu trả lời trước đó cho câu hỏi này.

Cũng xử lý đúng cách IDicitatic (ExpandoObject / dynamic) thường cần thiết khi xử lý nội dung phản ánh này.

Không khuyến khích sử dụng trong các vòng lặp chặt chẽ và các đường dẫn nóng khác. Trong những trường hợp đó, bạn sẽ cần một số biên dịch cây biểu thức / bộ nhớ đệm / IL.

    public static IEnumerable<(string Name, object Value)> GetProperties(this object src)
    {
        if (src is IDictionary<string, object> dictionary)
        {
            return dictionary.Select(x => (x.Key, x.Value));
        }
        return src.GetObjectProperties().Select(x => (x.Name, x.GetValue(src)));
    }

    public static IEnumerable<PropertyInfo> GetObjectProperties(this object src)
    {
        return src.GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => !p.GetGetMethod().GetParameters().Any());
    }

-1

Tôi không thể làm cho bất kỳ cách nào ở trên hoạt động, nhưng cách này đã hiệu quả. Tên người dùng và mật khẩu cho DirectoryEntry là tùy chọn.

   private List<string> getAnyDirectoryEntryPropertyValue(string userPrincipalName, string propertyToSearchFor)
    {
        List<string> returnValue = new List<string>();
        try
        {
            int index = userPrincipalName.IndexOf("@");
            string originatingServer = userPrincipalName.Remove(0, index + 1);
            string path = "LDAP://" + originatingServer; //+ @"/" + distinguishedName;
            DirectoryEntry objRootDSE = new DirectoryEntry(path, PSUsername, PSPassword);
            var objSearcher = new System.DirectoryServices.DirectorySearcher(objRootDSE);
            objSearcher.Filter = string.Format("(&(UserPrincipalName={0}))", userPrincipalName);
            SearchResultCollection properties = objSearcher.FindAll();

            ResultPropertyValueCollection resPropertyCollection = properties[0].Properties[propertyToSearchFor];
            foreach (string resProperty in resPropertyCollection)
            {
                returnValue.Add(resProperty);
            }
        }
        catch (Exception ex)
        {
            returnValue.Add(ex.Message);
            throw;
        }

        return returnValue;
    }
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.