c # foreach (properti dalam objek)… Apakah ada cara sederhana untuk melakukan ini?


92

Saya memiliki kelas yang berisi beberapa properti (semua adalah string jika ada bedanya).
Saya juga memiliki daftar, yang berisi banyak contoh kelas yang berbeda.

Saat membuat beberapa tes unit untuk kelas saya, saya memutuskan saya ingin mengulang melalui setiap objek dalam daftar dan kemudian mengulang melalui setiap properti objek itu ...

Saya pikir melakukan ini akan sesederhana ...

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

Tapi ini tidak berhasil! :( Saya mendapatkan kesalahan ini ...

"Pernyataan foreach tidak dapat beroperasi pada variabel jenis 'Application.Object' karena 'Application.Object' tidak berisi definisi publik untuk 'GetEnumerator'"

Adakah yang tahu cara melakukan ini tanpa banyak if dan loop atau tanpa masuk ke dalam sesuatu yang terlalu rumit?


5
Di masa mendatang, tolong jangan katakan "Itu tidak berhasil" dalam pertanyaan. Sebagai gantinya, tentukan masalah yang Anda hadapi (kesalahan kompilator, dll). Terima kasih!
Robert Harvey

2
Diperbarui! Terima kasih atas perhatiannya Robert
Jammerz858

Jawaban:


143

Cobalah ini:

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

Juga harap dicatat bahwa Type.GetProperties()memiliki kelebihan beban yang menerima satu set bendera pengikat sehingga Anda dapat memfilter properti pada kriteria yang berbeda seperti tingkat aksesibilitas, lihat MSDN untuk lebih jelasnya: Type.GetProperties Method (BindingFlags) Last but not least jangan lupa untuk tambahkan referensi perakitan "system.Reflection".

Misalnya untuk menyelesaikan semua properti publik:

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

Tolong beri tahu saya apakah ini berfungsi seperti yang diharapkan.


4
Setelah Anda memiliki pegangan pada properti objek, apakah ada cara untuk mengambil nilai dari setiap properti? yaitu Nama atau Kode Pos misalnya
JsonStatham

36

Anda dapat melakukan perulangan melalui semua properti non-indeks dari sebuah objek seperti ini:

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

Karena pengindeksGetProperties() mengembalikan serta properti sederhana, Anda memerlukan filter tambahan sebelum menelepon untuk mengetahui bahwa itu aman untuk diteruskanGetValuenull sebagai parameter kedua.

Anda mungkin perlu memodifikasi filter lebih lanjut untuk menyingkirkan properti hanya-tulis dan sebaliknya tidak dapat diakses.


+1 untuk hanya melakukan sesuatu dengan properti yang benar-benar dapat digunakan - Anda mungkin juga ingin memfilter properti hanya-tulis.

@hvd Ini adalah poin yang sangat baik pada properti hanya-tulis! Saya hampir melupakannya. Kode saya akan macet jika menemukan properti dengan nullgetter, tetapi saya yakin OP akan mencari cara untuk mendapatkan hanya properti yang dia butuhkan.
Sergey Kalinichenko

27

Anda hampir sampai, Anda hanya perlu mendapatkan properti dari tipe, daripada mengharapkan properti dapat diakses dalam bentuk koleksi atau tas properti:

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

Dari sana Anda dapat mengakses seperti ini :

property.Name
property.GetValue(obj, null)

Dengan GetValueparameter kedua akan memungkinkan Anda untuk menentukan nilai indeks, yang akan bekerja dengan properti yang mengembalikan koleksi - karena string adalah kumpulan karakter, Anda juga dapat menentukan indeks untuk mengembalikan karakter jika perlu.


1
Apakah saya mengecewakan seseorang? Saya terbuka untuk mengetahui apa yang salah tentang ini, jika tidak saya mungkin tidak akan pernah belajar.
Berikan Thomas

Anda mungkin mendapat suara negatif ketika kode Anda salah (sebelum ninja Anda mengedit).
Robert Harvey

20

Tentu saja, tak masalah:

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

mengapa Anda menambahkan baris ini? if (item == null) continue;Secara pribadi, saya pikir jika Anda mendapat objek null pada saat itu, ada yang salah jauh sebelumnya dan di situlah validasi seharusnya, atau apakah saya salah?
Rafael Herscovici

@ Dementic: Tentu, kita dapat mengatakan bahwa urutan harus berisi referensi bukan-nol.
Eric Lippert

3

Gunakan Refleksi untuk melakukan ini

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

2

Saya mencari jawaban untuk pertanyaan serupa di halaman ini, saya menulis jawaban untuk beberapa pertanyaan serupa yang mungkin dapat membantu orang yang masuk ke halaman ini.

Daftar Kelas

Kelas List <T> merepresentasikan daftar objek yang dapat diakses oleh indeks. Itu berada di bawah namespace System.Collection.Generic. Kelas daftar dapat digunakan untuk membuat kumpulan berbagai jenis seperti bilangan bulat, string, dll. Kelas daftar juga menyediakan metode untuk mencari, mengurutkan, dan memanipulasi daftar.

Kelas dengan properti :

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

ATAU, Kelas dengan bidang :

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

}

ATAU, Daftar objek (tanpa sel yang sama):

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

ATAU, Daftar objek (Harus memiliki sel yang sama):

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

ATAU, Daftar objek (dengan kunci):

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

ATAU, Daftar Kamus

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

Semoga berhasil..


0

Sedikit peringatan, jika "melakukan beberapa hal" berarti memperbarui nilai properti sebenarnya yang Anda kunjungi DAN jika ada properti tipe struct di sepanjang jalur dari objek root ke properti yang dikunjungi, perubahan yang Anda buat pada properti tersebut akan tidak tercermin pada objek root.


0

Solusi salin-tempel (metode ekstensi) sebagian besar didasarkan pada tanggapan sebelumnya untuk pertanyaan ini.

Juga menangani IDicitonary (ExpandoObject / dynamic) dengan benar yang sering dibutuhkan saat menangani hal-hal yang direfleksikan ini.

Tidak disarankan untuk digunakan pada loop yang rapat dan jalur panas lainnya. Dalam kasus tersebut, Anda akan memerlukan kompilasi pohon emit / ekspresi caching / 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

Saya tidak bisa mendapatkan salah satu cara di atas untuk bekerja, tetapi ini berhasil. Nama pengguna dan sandi untuk DirectoryEntry adalah opsional.

   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;
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.