2010-11-19 5 views
11

Tamam, ilk başta bunun yeterince kolay olduğunu düşündüm ve belki de çok yorgunum - ama yapmaya çalışıyorum. Ben yapabilmek için gerekenlerÖzyinelemeli Bir Nesnenin Özelliklerini ve Çocuk Özelliklerini Bul

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; } 
} 

, görünecektir ki (TÜM çocuk özelliklerine VE çocuk özelliklerinin çocuk mülkler dahil) bir dizeye içinde Kaplar özellik adlarını 'düzleştirmek': Ben şu nesneleri Say şunun gibi:

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

Bu herhangi bir anlam ifade ediyor mu? Kafamın etrafına sarılabilirim. Hepinize sınıfları işaretlemek için önermek

+0

Çocuk mülkünün ne olduğunu nasıl belirleyeceğiniz konusunda net olmalısınız. Burada, List türünün T tipi olarak düzleştirileceğini varsayarsınız. Bir mülk varsa, kamuya açık Telefon Numarası {get; set; } ( Listesi yerine)? Bu farklı ele alınabilir mi? Mülkleriniz her zaman ilkel tipler mi yoksa Listesi mi olacak? – mellamokb

+0

[İç içe geçmiş sınıflar ve özyineleme] 'nin olası kopyası (http://stackoverflow.com/questions/811098/nested-classes-and-recursion) – nawfal

cevap

12

, bunu her zaman olacaktır eğer böyle bir şey kullanabilirsiniz, sen benim Başına yorum bu

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

Teşekkür ederiz! İlk kez çalıştı – Wayne

+0

@ The_Smallest: Merhaba .. Buna benzer bir şeye ihtiyacım var. Ancak özelliklerine eklenen özel özellik var. Özel özniteliğe sahip tüm özelliklerin listesini almam gerekiyor. Nesne düzeyinde herhangi bir öznitelik kullanmak istemiyorum (Ekstre Adı). Ur kodunu kullanmaya ve bazı değişiklikler yapmaya çalışıyorum.Ama başarı yok. Lütfen yardım et. – Shetty

+0

@The_Smallest: Merhaba .. Buna benzer bir şeye ihtiyacım var. Ancak özelliklerine eklenen özel özellik var. Özel özniteliğe sahip tüm özelliklerin listesini almam gerekiyor. Türler iç içe olduğundan, özellikleri tüm iç tiplerde de almak istiyorum. Ur kodunu kullanmaya ve bazı değişiklikler yapmaya çalışıyorum.Ama başarı yok. Lütfen yardım et. – Shetty

0

gibi bir şey yapabileceğini sonra özel ayrıntı ile, kapmak gerekir Çocuk türüne bağlamak istediğiniz genel Liste türü olun. IteratePropertiesÖrneğin, türün özelliklerini ve genel bir Liste aracılığıyla bağlanan tüm alt tiplerin özelliklerini yinelemeli olarak verilen türün özellikleri üzerinde yineleyici bir ifadedir.

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; 
     } 
    } 
} 

Not: Bu kodu doğru ardışık olarak özelliklerinden biri bir türü olarak kendisini içeren bir tür bir işlem yapılmayacaktır. Böyle bir tür üzerinde yinelemeye çalışmak, @Dementic (teşekkürler!) Ile işaret edildiği gibi StackOverflowException ile sonuçlanacaktır.

+0

'da bu bir StackOverflow'u atar. – Dementic

+0

@Dementic: OP'nin orijinal sınıflarını kullanarak tekrar denedim. LINQPad'da iyi çalışır ve Container.Name, Container.Address.AddressLine1, Container.Address.AddressLine2, Container.Address.Telephone.CellPhone' çıktılarını verir. Nerede olduğunu nereden anlatabilir misin? Kendini tekrar tekrar referans gösteren bir sınıf türünde test ediyor muydunuz? Eğer öyleyse, bu kodun kullanılmaması gereken bir durumdur. – mellamokb

+0

evet, denedim, bir SO aldınız, kodunuzu düzeltmeniz gerekiyor bu yüzden özellik ziyaretçileri bunu alamıyor (yani, tüm tabanları kaplıyor) – Dementic