我有以下类(class)
public class Car
{
public int CarId { get; set;}
public string Description { get; set;}
public Engine Engine { get; set;}
}
public class Engine
{
public int EngineId { get; set;}
public int Description { get; set;}
}
现在我想迭代 Car 中的所有属性和 Engine 中的所有属性,我不想硬编码属性名称“Car or Engine”
获取 Car 的所有属性的示例,其中 obj
是 Car 的实例。
var properties = obj.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
但这不会迭代 Engine 的属性。
FlattenHierarchy
并不像您想象的那样,而是遵循静态成员的继承层次结构。
如果你想获得对象的子属性,你需要自己做:
static IEnumerable<PropertyInfo> FlattenProperties(Type type)
{
// Assumption #1: you do not want "simple" types enumerated
if (!type.IsClass)
return Enumerable.Empty<PropertyInfo>();
// Assumption #2: you want to ignore "the usual suspects"
if (type.Namespace != null && type.Namespace.StartsWith("System"))
return Enumerable.Empty<PropertyInfo>();
// Assumption #3: your class hierarchy won't destroy recursion
// Assumption #4: you simply want the PropertyInfo
return type.GetProperties(BindingFlags.FlattenHierarchy
| BindingFlags.Instance
| BindingFlags.Public)
.SelectMany(pi => new[] { pi }
.Concat(FlattenProperties(pi.PropertyType)));
}
如果在您 (a) 知道递归的深度,并且 (b) 有办法改变代码的代码中使用它,我建议为这些类型创建一个基类、接口(interface)或属性/属性。
// Replace Assumptions #1 and #2 above with this:
// Assumption #5: given interface ISomething { }
if (!typeof(ISomething).IsAssignableFrom(type))
return Enumerable.Empty<PropertyInfo>();
如果您需要“属性树”(即假设 #4 不正确):
static IEnumerable<IEnumerable<PropertyInfo>> FlattenProperties(
Type type,
IEnumerable<PropertyInfo> ancestors = null)
{
// change to Assumptions #1/#2 or #5 to yield break
// ...
ancestors = ancestors ?? Enumerable.Empty<PropertyInfo>();
var properties = type.GetProperties(
BindingFlags.FlattenHierarchy
| BindingFlags.Instance
| BindingFlags.Public);
foreach (var property in properties)
{
// again, Assumption #3: your class hierarchy won't destroy recursion
// Assumption #6: you actually want the initial nested property too
yield return ancestors.Concat(new[] { property });
foreach (var nested in FlattenProperties(
property.PropertyType,
ancestors.Concat(new [] { property })))
{
yield return nested;
}
}
}
在第二种情况下,产生的输出类似于:
// foreach (var tree in FlattenProperties(typeof(Car)))
// {
// Console.WriteLine("{0}", String.Join(".", tree.Select(pi => pi.Name)));
// }
CarId
Description
Engine
Engine.EngineId
Engine.Description