c # foreach (nesnede özellik)… Bunu yapmanın basit bir yolu var mı?


92

Birkaç özellik içeren bir sınıfım var (herhangi bir fark yaratıyorsa tümü dizelerdir).
Ayrıca, sınıfın birçok farklı örneğini içeren bir listem var.

Sınıflarım için bazı birim testleri oluştururken, listedeki her nesnede döngü yapmak ve ardından o nesnenin her özelliğinde döngü yapmak istediğime karar verdim ...

Bunu yapmanın basit olacağını düşündüm ...

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

Ama bu işe yaramadı! :( Bu hatayı alıyorum ...

"foreach ifadesi, 'Application.Object' türündeki değişkenler üzerinde çalışamaz çünkü 'Application.Object', 'GetEnumerator' için genel bir tanım içermiyor"

Bunu tonlarca ifs ve döngü olmadan veya çok karmaşık bir şeye girmeden yapmanın bir yolunu bilen var mı?


5
İleride lütfen bir soruda "İşe yaramıyor" demeyin. Bunun yerine, yaşadığınız sorunu belirtin (derleyici hatası, vb.). Teşekkürler!
Robert Harvey

2
Güncellenmiş! Teşekkürler Robert
Jammerz858

Yanıtlar:


143

Bunu bir deneyin:

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

Ayrıca Type.GetProperties(), erişilebilirlik seviyesi gibi farklı kriterlere göre özellikleri filtreleyebilmeniz için bir dizi bağlama bayrağını kabul eden bir aşırı yükleme olduğunu lütfen unutmayın, daha fazla ayrıntı için MSDN'ye bakın: Type.GetProperties Yöntemi (BindingFlags) Son ama en az değil "system.Reflection" derleme başvurusunu ekleyin.

Örneğin tüm genel mülkleri çözmek için:

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

Lütfen bunun beklendiği gibi çalışıp çalışmadığını bana bildirin.


4
Nesnelerin özellikleri üzerinde bir tutamaca sahip olduğunuzda, her özelliğin değerini yakalama yolu var mı? ör. bir İsim veya Posta Kodu
JsonStatham

36

Bir nesnenin tüm dizinlenmemiş özelliklerinde aşağıdaki gibi döngü yapabilirsiniz:

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

Yana GetProperties()döner dizinleyicilerle yanı sıra basit özelliklere, sen çağırmadan önce ek bir filtre ihtiyaç GetValueGeçmesi güvenli olduğunu bilmek nullikinci parametre olarak.

Yalnızca yazılır ve başka şekilde erişilemeyen özellikleri ayıklamak için filtreyi daha fazla değiştirmeniz gerekebilir.


Yalnızca gerçekten kullanılabilen özelliklerle bir şeyler yapmak için +1 - salt yazılır özellikleri de filtrelemek isteyebilirsiniz.

@hvd Bu, salt yazılabilir özelliklerde mükemmel bir nokta! Onları neredeyse unutuyordum. nullKodum, alıcıya sahip bir özellik ile karşılaşırsa çökecek , ancak eminim ki OP yalnızca ihtiyaç duyduğu özellikleri nasıl elde edeceğini anlayacaktır.
Sergey Kalinichenko

27

Neredeyse orada, mülklerin bir koleksiyon veya mülk çantası şeklinde erişilebilir olmasını beklemek yerine, mülkleri türden almanız yeterlidir:

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

Oradan şu şekilde erişebilirsiniz :

property.Name
property.GetValue(obj, null)

GetValueİkinci parametre ile , koleksiyonları döndüren özelliklerle çalışacak dizin değerlerini belirlemenize izin verir - bir dize bir karakter koleksiyonu olduğundan, gerekirse bir karakter döndürmek için bir dizin de belirtebilirsiniz.


1
Birini üzdüm mü? Bunda neyin yanlış olduğunu bilmeye açığım, yoksa asla öğrenemeyebilirim.
Grant Thomas

Muhtemelen kodunuz yanlış olduğunda (ninja düzenlemenizden önce) olumsuz oy almışsınızdır.
Robert Harvey

20

Elbette, hiç sorun değil:

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

neden bu satırı ekledin if (item == null) continue;şahsen, bence o noktada boş bir nesneye sahipseniz, çok daha önce bir şeyler ters gitti ve doğrulama nerede olmalı, yoksa yanılıyor muyum?
Rafael Herscovici

@Dementic: Elbette, dizinin boş olmayan referanslar içermesi gerektiğini söyleyebiliriz.
Eric Lippert

3

Bunu yapmak için Düşünceyi kullanın

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

2

Bu sayfada benzer bir sorunun cevabını aradım, bu sayfaya giren kişilere yardımcı olabilecek birkaç benzer sorunun cevabını yazdım.

Sınıf Listesi

Liste <T> sınıfı, indeksle erişilebilen nesnelerin listesini temsil eder. System.Collection.Generic ad alanı altında gelir. List sınıfı, tamsayılar, dizeler vb. Gibi farklı türlerden oluşan bir koleksiyon oluşturmak için kullanılabilir. List sınıfı ayrıca listeleri aramak, sıralamak ve işlemek için yöntemler sağlar.

Mülkiyetli sınıf :

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

VEYA, alanlı sınıf :

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

}

VEYA, Nesnelerin listesi (aynı hücreler olmadan):

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

VEYA, Nesnelerin listesi (Aynı hücrelere sahip olmalıdır):

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

VEYA, Nesnelerin listesi (anahtarlı):

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

OR, Sözlük Listesi

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

İyi şanslar..


0

Küçük bir uyarı: "bir şeyler yap", ziyaret ettiğiniz gerçek özelliğin değerini güncellemek anlamına geliyorsa VE kök nesneden ziyaret edilen özelliğe giden yol boyunca bir yapı türü özelliği varsa, özellikte yaptığınız değişiklik kök nesneye yansıtılmaz.


0

Çoğunlukla bu soruya verilen önceki yanıtlara dayanan bir kopyala yapıştır çözümü (uzatma yöntemleri).

Ayrıca, bu yansıyan şeylerle uğraşırken sıklıkla ihtiyaç duyulan IDicitonary (ExpandoObject / dynamic) 'yi de düzgün bir şekilde işler.

Dar döngülerde ve diğer sıcak yollarda kullanılması tavsiye edilmez. Bu durumlarda, bazı önbelleğe alma / IL yayma / ifade ağacı derlemesine ihtiyacınız olacaktır.

    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

Yukarıdaki çalışma yöntemlerinden hiçbirini alamadım, ancak bu işe yaradı. DirectoryEntry için kullanıcı adı ve şifre isteğe bağlıdır.

   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;
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.