递归获取对象的属性和子属性

好吧,所以起初我觉得这很容易,也许就是这样,我太累了 – 但这就是我想做的事情。 说我有以下对象:

public class Container { public string Name { get; set; } public List
Addresses { get; set; } } public class Address { public string AddressLine1 { get; set; } public string AddressLine2 { get; set; } public List Telephones { get; set; } } public class Telephone { public string CellPhone { get; set; } }

我需要做的是,将容器属性名称’flatten’到一个字符串(包括所有子属性和子属性的子属性),如下所示:

 Container.Name, Container.Addresses.AddressLine1, Container.Addresses.AddressLine2, Container.Addresses.Telephones.CellPhone 

这有任何意义吗? 我似乎无法将它包裹在我的脑海里。

我建议你用自定义属性标记所有类,你需要抓取,之后你可以做这样的事情

  class Program { static void Main(string[] args) { var lines = ExtractHelper.IterateProps(typeof(Container)).ToArray(); foreach (var line in lines) Console.WriteLine(line); Console.ReadLine(); } } static class ExtractHelper { public static IEnumerable IterateProps(Type baseType) { return IteratePropsInner(baseType, baseType.Name); } private static IEnumerable IteratePropsInner(Type baseType, string baseName) { var props = baseType.GetProperties(); foreach (var property in props) { var name = property.Name; var type = ListArgumentOrSelf(property.PropertyType); if (IsMarked(type)) foreach (var info in IteratePropsInner(type, name)) yield return string.Format("{0}.{1}", baseName, info); else yield return string.Format("{0}.{1}", baseName, property.Name); } } static bool IsMarked(Type type) { return type.GetCustomAttributes(typeof(ExtractNameAttribute), true).Any(); } public static Type ListArgumentOrSelf(Type type) { if (!type.IsGenericType) return type; if (type.GetGenericTypeDefinition() != typeof(List<>)) throw new Exception("Only List are allowed"); return type.GetGenericArguments()[0]; } } [ExtractName] public class Container { public string Name { get; set; } public List
Addresses { get; set; } } [ExtractName] public class Address { public string AddressLine1 { get; set; } public string AddressLine2 { get; set; } public List Telephones { get; set; } } [ExtractName] public class Telephone { public string CellPhone { get; set; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)] public sealed class ExtractNameAttribute : Attribute { }

根据我的评论,如果它总是一个你想要链接到子类型的通用List类型,你可以使用这样的东西。 IteratePropertiesRecursively是给定类型属性的迭代器,它将递归枚举类型的属性以及通过genericsList链接的所有子类型。

 protected void Test() { Type t = typeof(Container); string propertyList = string.Join(",", IteratePropertiesRecursively("", t).ToArray()); // do something with propertyList } protected IEnumerable IteratePropertiesRecursively(string prefix, Type t) { if (!string.IsNullOrEmpty(prefix) && !prefix.EndsWith(".")) prefix += "."; prefix += t.Name + "."; // enumerate the properties of the type foreach (PropertyInfo p in t.GetProperties()) { Type pt = p.PropertyType; // if property is a generic list if (pt.Name == "List`1") { Type genericType = pt.GetGenericArguments()[0]; // then enumerate the generic subtype foreach (string propertyName in IteratePropertiesRecursively(prefix, genericType)) { yield return propertyName; } } else { // otherwise enumerate the property prepended with the prefix yield return prefix + p.Name; } } } 

注意:此代码将无法正确处理以其递归方式将自身包含为其某个属性类型的类型。 试图迭代这样的类型将导致StackOverflowException ,正如@Dementic所指出的那样(谢谢!)。