2011-02-25 11 views
6

Bir Baskı yöntemi böyle olması diyelim:Bilinmeyen bir koleksiyonda değerler yinelemek ve yazdırmak için genel bir yöntem var mı?

private static void Print(IEnumerable items) 
{ 
    // Print logic here 
} 

Bir tablo gibi tüm alanları yazdırmalısınız bu yazdır yöntemi bir koleksiyon sınıfını geçmek istiyorum. Örneğin, giriş koleksiyonum "Kişiler" veya "Siparişler" veya "Otomobiller" olabilir.

"Otomobil" koleksiyonunu Yazdırma yöntemine iletirsem, "Araba" gibi : Yap, Renk, Fiyat, Sınıf vb.

Koleksiyonun çalışma zamanını çalışma zamanına kadar bilmem. TypeDescriptors ve PropertyDescriptorCollection kullanarak bir çözüm denedim ve başardım. Ancak, bunun iyi bir çözüm olduğunu hissetmiyorum. İfadeleri veya jenerikleri kullanarak bunu başarmanın başka bir yolu var mı?

+1

her şeyin bir 'IMyToString' arabirimini uygulamak zorunda (varsayarak ToString doğrudan geçersiz değildir) ve bir sonra IEnumerable 'al. Elbette başka yöntemler de vardır, ancak genellikle bir haritalamaya (TypeConverters bir haritalama şeklidir) veya RTTI'yı başka şekillerde kullanmaya dayanır. Standart polimorfizm modelini önerdiği için –

cevap

6

Böyle yazdır uygulamak olabilir:

static void Print<T>(IEnumerable<T> items) 
{ 
    var props = typeof(T).GetProperties(); 

    foreach (var prop in props) 
    { 
     Console.Write("{0}\t", prop.Name); 
    } 
    Console.WriteLine(); 

    foreach (var item in items) 
    { 
     foreach (var prop in props) 
     { 
      Console.Write("{0}\t", prop.GetValue(item, null)); 
     } 
     Console.WriteLine(); 
    } 
} 

Bu sadece her öğenin üzerine daha sonra, özelliğin adını yazdırmak için sınıfın her bir özellik üzerinde baskılar döngüler ve her öğe için bu değerlerini yazdırır özellikleri.

Burada jenerikler kullanmanız gerektiğini iddia ediyorum (diğer cevaplardaki önerilerin aksine); tablo başlıklarını yazdırabilmeniz için koleksiyondaki öğelerin tek bir tür olmasını istiyorsunuz.

Tablo formatı için this question cevabını kontrol edebilirsiniz.

+0

Tam olarak aradığım şey.Çok teşekkürler :) –

+0

Bu, aradığım şey için çalışıyor; bu, Nesne'nin Özellik Adını (ları) bir kez yazdırmak ve ardından Listedeki her öğe için değerleri yazdırmaktır. Teşekkürler! – Shiva

7

Görüntülemek istediğiniz tüm bilgileri içerecek şekilde nesnenin ToString() yöntemini geçersiz kılın ve istediğiniz zaman onu istediğiniz zaman arayın. İfadelere veya jeneriklere gerek yok.

+1

+1. Sınıflar mühürlenmişse, o zaman "Ziyaretçi Kalıbı" (ayrıntılı desen eşlemesi ;-) kullanılabilir). –

+0

Ve .net ziyaretçi modelinde uzantı yöntemlerinden başka bir şey yoktur. – Pradeep

+0

Yukarıdaki çözüm gerçekten çok iyi. Ama başka bir sorunum var. Örneğin, örneğin, bilinmeyen bir koleksiyonum var ise, 'var sonuç =' p 'dan seçimlerden p seçin. P.ID = o.PersonID, yeni {p.Name, o.Name}; 'Yazdır (sonuç); ”Bu durumda, bunu nasıl başarabilirim? –

3

Ne tür olduğunu bilmiyorsanız - yani herhangi bir tür olabilir - o zaman en iyi seçenek yansıma kullanmaktır. Bu iyi bir çözüm. Neden iyi bir çözüm olmadığını düşünüyorsun?

1

Bu örnek performans kullanarak İfadeler İçin sizin için bir yazdırma yöntemi önbelleğe: Eğer jenerik ile yapabileceğiniz en iyi Hakkında

class MyObject 
    { 
     public int Property1 { get; set;} 
     public string Property2 { get; set; } 
    } 
    class MyOtherObject 
    { 
     public int Property3 { get; set; } 
     public string Property4 { get; set; } 
    } 
    static void Main(string[] args) 
    { 
     Array.ForEach(new[] 
     { 
      new MyObject { Property1 = 1, Property2 = "P" }, 
      new MyObject { Property1 = 2, Property2 = "Q" } 
     }, Print); 
     Array.ForEach(new[] 
     { 
      new MyOtherObject { Property3 = 3, Property4 = "R" }, 
      new MyOtherObject { Property3 = 4, Property4 = "S" } 
     }, Print); 
     Console.ReadKey(); 
    } 
    static void Print<T>(T item) 
    { 
     ObjectPrinter<T>.PrintAction(item, Console.Out); 
    } 
    static class ObjectPrinter<T> 
    { 
     public static readonly Action<T, TextWriter> PrintAction = CreatePrintAction(); 
     private static Action<T, TextWriter> CreatePrintAction() 
     { 
      ParameterExpression item = Expression.Parameter(typeof(T), "item"); 
      ParameterExpression writer = Expression.Parameter(typeof(TextWriter), "writer"); 
      var writeLineMethod = typeof(TextWriter).GetMethod("WriteLine", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string) }, null); 
      var concatMethod = typeof(string).GetMethod("Concat", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(object), typeof(object) }, null); 
      var writeDashedLine = Expression.Call(
       writer, 
       writeLineMethod, 
       Expression.Constant(
        new String('-', 50) 
       ) 
      ); 
      var lambda = Expression.Lambda<Action<T, TextWriter>>(
       Expression.Block(
        writeDashedLine, 
        Expression.Block(
         from property in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance) 
         where property.GetGetMethod().GetParameters().Length == 0 
         select Expression.Call(
          writer, 
          writeLineMethod, 
          Expression.Call(
           null, 
           concatMethod, 
           Expression.Constant(
            property.Name + ":" 
           ), 
           Expression.Convert(
            Expression.Property(
             item, 
             property 
            ), 
            typeof(object) 
           ) 
          ) 
         ) 
        ), 
        writeDashedLine 
       ), 
       item, 
       writer 
      ); 
      return lambda.Compile(); 
     } 
    } 
İlgili konular