c # foreach (свойство в объекте) Есть ли простой способ сделать это?

У меня есть класс, содержащий несколько свойств (все являются строками, если это имеет какое-либо значение).
У меня также есть список, который содержит множество различных экземпляров класса.

Создавая несколько модульных тестов для своих классов, я решил, что хочу перебрать каждый объект в списке, а затем перебрать каждое свойство этого объекта ...

Я думал сделать это так же просто, как ...

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

Но это не сработало! :( У меня такая ошибка ...

«Оператор foreach не может работать с переменными типа Application.Object, потому что Application.Object не содержит общедоступного определения для GetEnumerator»

Кто-нибудь знает, как это сделать без тонны if и циклов или не вдаваясь во что-то слишком сложное?


person Jammerz858    schedule 27.03.2012    source источник
comment
В будущем, пожалуйста, не говорите, что это не работает в вопросе. Вместо этого укажите проблему, с которой вы столкнулись (ошибка компилятора и т. Д.). Спасибо!   -  person Robert Harvey    schedule 27.03.2012
comment
Обновлено! Спасибо за внимание, Роберт   -  person Jammerz858    schedule 12.04.2012


Ответы (10)


Попробуйте:

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

Также обратите внимание, что Type.GetProperties() имеет перегрузку, которая принимает набор флагов привязки, поэтому вы можете отфильтровывать свойства по другим критериям, таким как уровень доступности. Дополнительные сведения см. В MSDN: Метод Type.GetProperties (BindingFlags) И последнее, но не менее важное: не забудьте добавить ссылку на сборку" system.Reflection ".

Например, чтобы разрешить все общедоступные свойства:

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

Пожалуйста, дайте мне знать, работает ли это должным образом.

person sll    schedule 27.03.2012
comment
Если у вас есть дескриптор свойств объекта, есть ли способ получить значение каждого свойства? например, имя или почтовый индекс - person JsonStatham; 01.10.2015

Вы можете просмотреть все неиндексированные свойства объекта следующим образом:

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

Поскольку GetProperties() возвращает индексаторы, а также простые свойства, вам понадобится дополнительный фильтр перед вызовом GetValue, чтобы знать, что можно безопасно передавать null в качестве второго параметра.

Возможно, вам придется дополнительно изменить фильтр, чтобы исключить свойства, доступные только для записи или недоступные по другим причинам.

person Sergey Kalinichenko    schedule 27.03.2012
comment
+1 за то, что вы делаете что-то только со свойствами, которые действительно могут быть использованы - вы также можете отфильтровать свойства, доступные только для записи. - person ; 27.03.2012
comment
@hvd Это отличный отзыв о свойствах только для записи! Я почти забыл о них. Мой код выйдет из строя, если встретит свойство с null геттером, но я уверен, что OP выяснит, как получить только те свойства, которые ему нужны. - person Sergey Kalinichenko; 27.03.2012

Вы почти готовы, вам просто нужно получить свойства из типа, а не ожидать, что свойства будут доступны в форме коллекции или пакета свойств:

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

Отсюда вы можете получить доступ следующим образом:

property.Name
property.GetValue(obj, null)

С GetValue второй параметр позволит вам указать значения индекса, которые будут работать со свойствами, возвращающими коллекции - поскольку строка представляет собой набор символов, вы также можете указать индекс для возврата символа, если это необходимо.

person Grant Thomas    schedule 27.03.2012
comment
Я кого-то обидел? Я открыт для понимания, что в этом плохого, иначе я бы никогда не узнал. - person Grant Thomas; 27.03.2012
comment
Вы, вероятно, получили голос против, когда ваш код был неправильным (до редактирования ниндзя). - person Robert Harvey; 27.03.2012

Конечно, нет проблем:

foreach(object item in sequence)
{
    if (item == null) continue;
    foreach(PropertyInfo property in item.GetType().GetProperties())
    {
        // do something with the property
    }
}
person Eric Lippert    schedule 27.03.2012
comment
зачем вы добавили эту строчку? if (item == null) continue; лично, я думаю, что если в этот момент у вас есть нулевой объект, что-то пошло не так намного раньше, и именно здесь должна быть проверка, или я ошибаюсь? - person Rafael Herscovici; 01.12.2016
comment
@Dementic: Конечно, можно сказать, что последовательность должна содержать ненулевые ссылки. - person Eric Lippert; 02.12.2016

Используйте для этого Reflection

SomeClass A = SomeClass(...)
PropertyInfo[] properties = A.GetType().GetProperties();
person Arion    schedule 27.03.2012

Я искал ответ на аналогичный вопрос на этой странице, я написал ответы на несколько похожих вопросов, которые могут помочь людям, которые заходят на эту страницу.

Список классов < / сильный>

Список ‹T› класс представляет собой список объектов, к которым можно получить доступ по индексу. Он входит в пространство имен System.Collection.Generic. Класс List может использоваться для создания коллекции различных типов, таких как целые числа, строки и т. Д. Класс List также предоставляет методы для поиска, сортировки и управления списками.

Класс с собственностью:

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

ИЛИ, Класс с полем:

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

}

ИЛИ, Список объектов (без одинаковых ячеек):

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

ИЛИ, Список объектов (в нем должны быть одинаковые ячейки):

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

ИЛИ, Список объектов (с ключом):

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

ИЛИ, Список словарей

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

Удачи..

person Sajad Mirzaei    schedule 25.06.2020

Небольшое предостережение: если «сделать что-нибудь» означает обновление значения фактического свойства, которое вы посещаете, И если есть свойство типа структуры на пути от корневого объекта к посещенному свойству, изменение, которое вы сделали в свойстве, будет не отражаться на корневом объекте.

person Dogu Arslan    schedule 24.01.2017

Решение для копирования и вставки (методы расширения) в основном основано на более ранних ответах на этот вопрос.

Также правильно обрабатывает IDicitonary (ExpandoObject / dynamic), который часто требуется при работе с этим отраженным материалом.

Не рекомендуется использовать в узких петлях и других горячих дорожках. В этих случаях вам понадобится некоторая компиляция дерева кэширования / вывода 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());
    }
person Zar Shardan    schedule 08.10.2019

Для меня решением было изменить GetProperties () на GetRuntimeProperties ().

  static void EnumObject(ShareCollection obj)
    {
        foreach (PropertyInfo property in obj.GetType().GetRuntimeProperties())
        {
            property.GetValue(obj);
        }
    }
person Iván Kollár    schedule 14.03.2021

Я не мог заставить работать ни один из вышеперечисленных способов, но это сработало. Имя пользователя и пароль для DirectoryEntry необязательны.

   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;
    }
person Bbb    schedule 09.05.2018