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
具有属性的类:
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(对象中的属性)...有没有一种简单的方法可以做到这一点?的主要内容,如果未能解决你的问题,请参考以下文章
在实体中查找对象和加载实体、Foreach 或在哪里使用 LinQ ON C# 的最佳性能?
如何使用 SQL 命令从我的 DataTable 对象中使用 foreach-loop 更新 C# 中的 MS Access 数据库?