c# foreach(对象中的属性)...有没有一种简单的方法可以做到这一点?

Posted

技术标签:

【中文标题】c# foreach(对象中的属性)...有没有一种简单的方法可以做到这一点?【英文标题】:c# foreach (property in object)... Is there a simple way of doing this? 【发布时间】:2012-03-27 15:48:11 【问题描述】:

我有一个包含多个属性的类(如果有任何区别,它们都是字符串)。 我还有一个列表,其中包含该类的许多不同实例。

在为我的类创建一些单元测试时,我决定要遍历列表中的每个对象,然后遍历该对象的每个属性...

我认为这样做很简单......

foreach (Object obj in theList)

     foreach (Property theProperties in obj)
     
         do some stufff!!;
     

但这没有用! :( 我收到此错误...

“foreach 语句无法对 'Application.Object' 类型的变量进行操作,因为 'Application.Object' 不包含 'GetEnumerator' 的公共定义”

有没有人知道一种不用大量 if 和循环或不涉及太复杂的事情的方法?

【问题讨论】:

以后,请不要在问题中说“它不起作用”。相反,请指定您遇到的问题(编译器错误等)。谢谢! 更新了!感谢罗伯特的提醒 【参考方案1】:

试试这个:

foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())

   // do stuff here

另外请注意,Type.GetProperties() 有一个重载,它接受一组绑定标志,因此您可以根据不同的标准(例如可访问性级别)过滤掉属性,有关更多详细信息,请参阅 MSDN:Type.GetProperties Method (BindingFlags) 最后但同样重要的是不要忘记添加“system.Reflection”程序集引用。

例如解析所有公共属性:

foreach (var propertyInfo in obj.GetType()
                                .GetProperties(
                                        BindingFlags.Public 
                                        | BindingFlags.Instance))

   // do stuff here

请让我知道这是否按预期工作。

【讨论】:

一旦你掌握了对象的属性,有没有办法获取每个属性的值?即名称或邮政编码,例如 像这样:propertyInfo .GetValue(obj, null)【参考方案2】:

您可以像这样遍历对象的所有非索引属性:

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

由于GetProperties() 返回indexers 以及简单的属性,因此在调用GetValue 之前需要一个额外的过滤器,以知道将null 作为第二个参数传递是安全的。

您可能需要进一步修改过滤器以清除只写和其他不可访问的属性。

【讨论】:

+1 表示仅对可以实际使用的属性做一些事情——您可能还想过滤掉只写属性。 @hvd 这是只写属性的一个极好点!我几乎忘记了他们。如果遇到带有null getter 的属性,我的代码会崩溃,但我相信 OP 会弄清楚如何只获取他需要的属性。【参考方案3】:

你快到了,你只需要从类型中获取属性,而不是期望属性可以以集合或属性包的形式访问:

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

从那里you can access like so:

property.Name
property.GetValue(obj, null)

使用GetValue,第二个参数将允许您指定索引值,这将与返回集合的属性一起使用 - 因为字符串是字符的集合,如果需要,您还可以指定返回字符的索引。

【讨论】:

我惹恼了某人吗?我愿意知道这有什么问题,否则我可能永远学不会。 当您的代码错误时(在您的 ninja 编辑之前),您可能会被否决。【参考方案4】:

当然,没问题:

foreach(object item in sequence)

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

【讨论】:

为什么要添加这一行? if (item == null) continue; 就我个人而言,我认为如果你当时有一个空对象,那么早先出了点问题,那就是验证应该在哪里,或者我错了吗? @Dementic:当然,我们可以说序列必须包含非空引用。【参考方案5】:

使用反射来做到这一点

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

【讨论】:

【参考方案6】:

我在此页面上寻找类似问题的答案,我写了几个类似问题的答案,可能对进入此页面的人有所帮助。

Class List

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

OR,对象列表(带键):

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

祝你好运..

【讨论】:

【参考方案7】:

请注意,如果“做一些事情”意味着更新您访问的实际属性的值,并且如果从根对象到访问的属性的路径上有一个结构类型属性,那么您所做的更改该属性不会反映在根对象上。

【讨论】:

【参考方案8】:

一种复制粘贴解决方案(扩展方法),主要基于对此问题的早期回答。

还可以正确处理 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());
    

【讨论】:

【参考方案9】:

对我来说,解决方案是将 GetProperties() 更改为 GetRuntimeProperties()。

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

【讨论】:

【参考方案10】:

我无法获得上述任何一种工作方式,但这有效。 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;
    

【讨论】:

以上是关于c# foreach(对象中的属性)...有没有一种简单的方法可以做到这一点?的主要内容,如果未能解决你的问题,请参考以下文章

c# 如何获取列表中某个属性最大或最小的元素?

C#遍历对象属性

在实体中查找对象和加载实体、Foreach 或在哪里使用 LinQ ON C# 的最佳性能?

C#中的foreach循环怎么用?

如何使用 SQL 命令从我的 DataTable 对象中使用 foreach-loop 更新 C# 中的 MS Access 数据库?

我想在c#中使用foreach循环一一读取具有特定json对象数组的json文件数据