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

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

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

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

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

Но это не сработало!:(Я получаю эту ошибку...

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

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

10 ответов

Решение

Попробуйте это:

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

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

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

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

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

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

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 как второй параметр.

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

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

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

Оттуда вы можете получить доступ так:

property.Name
property.GetValue(obj, null)

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

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

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

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

Список классов

Класс List представляет список объектов, к которым можно получить доступ по индексу. Он входит в пространство имен 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);
    }
}

Удачи..

Используйте Reflection, чтобы сделать это

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

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

Также правильно обрабатывает 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());
    }

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

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

        static void EnumObject(ShareCollection obj)
    {
        foreach (PropertyInfo property in obj.GetType().GetRuntimeProperties())
        {
            property.GetValue(obj);
        }
    }

Я не мог получить ни один из вышеперечисленных способов работы, но это сработало. Имя пользователя и пароль для 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;
    }
Другие вопросы по тегам