2010-11-19 15 views
11

最初はこれが十分に簡単だと思っていましたが、多分それは疲れましたが、ここで私がやろうとしていることがあります。私は次のオブジェクトを持っていると言う:オブジェクトのプロパティと子プロパティを再帰的に取得

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

私が行うことができるように必要なもの、になります(すべての子プロパティと子のプロパティの子プロパティを含む)の文字列にしてコンテナのプロパティ名を「フラット化」されますこのように:

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

これは意味がありますか?私はそれを私の頭の周りに包むように見えない。

+0

子供の財産をどのように決定するかについては、明確にする必要があります。ここでは、List タイプがタイプTとしてフラット化されることを前提としています。プロパティがあった場合はどうでしょうか?public Telephone Number {get;セット; }(リストの代わりに)?それは異なって扱われるだろうか?あなたのプロパティは常にプリミティブ型かリストのどちらかになりますか?Tは複合型ですか? – mellamokb

+0

[ネストされたクラスと再帰]の可能な複製(http://stackoverflow.com/questions/811098/nested-classes-and-reursion) – nawfal

答えて

12

私はあなたが私のコメントパーこの

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<string> IterateProps(Type baseType) 
    { 
     return IteratePropsInner(baseType, baseType.Name); 
    } 

    private static IEnumerable<string> 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<T> are allowed"); 
     return type.GetGenericArguments()[0]; 
    } 
} 

[ExtractName] 
public class Container 
{ 
    public string Name { get; set; } 
    public List<Address> Addresses { get; set; } 
} 

[ExtractName] 
public class Address 
{ 
    public string AddressLine1 { get; set; } 
    public string AddressLine2 { get; set; } 
    public List<Telephone> 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 
{ } 
+0

ありがとう!初めての仕事 – Wayne

+0

@The_Smallest:こんにちは..私はこれに似たものが必要です。しかし、私はカスタム属性をプロパティに追加しました。私は、カスタム属性を持つすべてのプロパティのリストを取得する必要があります。オブジェクトレベルで属性を使用したくない(名前の抽出)。私は、urコードを使用していくつかの変更を加えることを試みています。しかし、成功はありません。助けてください。 – Shetty

+0

@ The_Smallest:こんにちは..私はこれに似たものが必要です。しかし、私はカスタム属性をプロパティに追加しました。私は、カスタム属性を持つすべてのプロパティのリストを取得する必要があります。型はネストされているので、すべての内部型のプロパティも取得したいと思います。私は、urコードを使用していくつかの変更を加えることを試みています。しかし、成功はありません。助けてください。 – Shetty

0

ような何かを行うことができ、その後、それは常にする場合は、あなたがこのようなものを使用することができ、カスタム属性を使用して、あなたがつかむために必要なすべてのクラスを、マークすることをお勧め子タイプにリンクする一般的なListタイプです。 IteratePropertiesRecursivelyは、指定された型のプロパティに対する反復子であり、型のプロパティと、ジェネリックListを介してリンクされたすべての子型を再帰的に列挙します。

protected void Test() 
{ 
    Type t = typeof(Container); 
    string propertyList = string.Join(",", IteratePropertiesRecursively("", t).ToArray<string>()); 
    // do something with propertyList 
} 

protected IEnumerable<string> 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; 
     } 
    } 
} 

注:このコードは正しく再帰的にその特性の一つのタイプとして自分自身を含むタイプを処理しません。このような型を反復しようとすると、@Dementic(指摘!)の指摘したようにStackOverflowExceptionになります。

+0

で、これはStackOverflowをスローします。 – Dementic

+0

@Dementic:私はOPの元のクラスを使ってもう一度それを試しました。 LINQPadで正常に動作し、 'Container.Name、Container.Address.AddressLine1、Container.Address.AddressLine2、Container.Address.Telephone.CellPhone'を出力します。 SOをどこで入手しているのか説明できますか?あなた自身を再帰的に参照するクラス型でテストしましたか?もしそうなら、それはこのコードを使用すべきではないユースケースです。 – mellamokb

+0

はい、私はクラスを試しましたが、あなたはコードを修正して、機能の訪問者がそれを得ないようにしなければなりません(つまり、すべての拠点をカバーします) – Dementic

関連する問題