【问题标题】:c# foreach (property in object)... Is there a simple way of doing this?c# foreach(对象中的属性)...有没有一种简单的方法可以做到这一点?
【发布时间】: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 和循环或不涉及太复杂的事情的方法?

【问题讨论】:

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

标签: c# properties foreach generic-list


【解决方案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;
                }
            

            【讨论】:

              猜你喜欢
              • 2013-07-29
              • 1970-01-01
              • 2014-02-26
              • 2012-02-25
              • 2017-05-13
              • 1970-01-01
              • 1970-01-01
              • 2011-06-28
              • 1970-01-01
              相关资源
              最近更新 更多