2013-03-05 10 views
5

Napisałem metodę, która akceptuje parametr ogólny, a następnie drukuje jego właściwości. Używam go do testowania mojej usługi internetowej. Działa, ale chcę dodać pewne funkcje, których nie wiem, jak zaimplementować. Chcę wydrukować wartości list, ponieważ teraz po prostu pisze System.Collection.Generic.List1, który jest oczekiwany.odbicie na liście i wartości drukowania

Oto mój kod do tej pory, to pracuje dla podstawowych typów (int, double etc.):

static void printReturnedProperties<T>(T Object) 
{ 
    PropertyInfo[] propertyInfos = null; 
    propertyInfos = Object.GetType().GetProperties(); 

    foreach (var item in propertyInfos) 
     Console.WriteLine(item.Name + ": " + item.GetValue(Object).ToString()); 
} 
+0

Dlaczego ta metoda jest ogólna (z parametrem typu "") i nigdy nie używasz 'T' do niczego? –

+0

@HighCore mógł zrobić 'PrintReturnedProperties (podklasa);' –

+5

Powinieneś użyć nazwy parametru innej niż 'Object', aby uchronić się przed pomyłkami z wbudowanym obiektem/Obiektem. –

Odpowiedz

5

Można zrobić coś takiego: (. Ja drukuje je jeden na linię, ale oczywiście, można robić różne)

static void printReturnedProperties(Object o) 
    { 
     PropertyInfo[] propertyInfos = null; 
     propertyInfos = o.GetType().GetProperties(); 



     foreach (var item in propertyInfos) 
     { 
      var prop = item.GetValue(o); 

      if(prop == null) 
      { 
       Console.WriteLine(item.Name + ": NULL"); 
      } 
      else 
      { 
       Console.WriteLine(item.Name + ": " + prop.ToString()); 
      } 


      if (prop is IEnumerable) 
      { 
       foreach (var listitem in prop as IEnumerable) 
       { 
        Console.WriteLine("Item: " + listitem.ToString()); 
       } 
      } 
     } 


    } 

Będzie on następnie wyliczyć poprzez dowolny IEnumerable i wydrukować poszczególne wartości

+0

Próbowałem tego, zanim zrobiłem coś złego. Tnx – gorgi93

3

elementów wewnątrz listy mogą być pobierane za pośrednictwem właściwości indeksatora Item. Ta właściwość akceptuje argument indeksu (występuje przeciążenie PropertyInfo.GetValue, które akceptuje tablicę object, podobnie jak MethodInfo.Invoke) i zwraca obiekt w tej pozycji.

int index = /* the index you want to get here */; 
PropertyInfo indexer = Object.GetProperty("Item"); 
object item = indexer.GetValue(Object, new object[] { index }); 
2

zazwyczaj drukuje listy z , między każdym elementem.

Aby było to łatwe Stworzyłem prostą metodę rozszerzenia:

public static class ListEx 
{ 
    public static string StringJoin<T>(this IEnumerable<T> items) 
    { 
     return string.Join(", ", items); 
    } 
} 

wywołać metodę jako myList.StringJoin().

Oczywiście można zmodyfikować metodę użycia innego separatora i zadzwonić bezpośrednio pod numer string.Join.

+1

Chciałbym osobiście po prostu użyć 'string.Join (", ", myList)'. – zneak

1

Oto fragment, przy założeniu, że lista jest typu T.

foreach (PropertyInfo item in propertyInfos) 
      { 
       Object obj = item.GetValue(object,null); 
       if (!obj.GetType().IsValueType) 
       { 
        if (obj.GetType() == typeof(String)) 
        { 
         Console.WriteLine(obj.ToString()); 
        } 
        else if (obj.GetType() == typeof(List<T>)) 
        { 
         //run a loop and print the list 

        } 
        else if (obj.GetType().IsArray) // this means its Array 
        { 
         //run a loop to print the array 
        } 

       } 
       else 
       { 
        //its primitive so we will convert to string 
        Console.WriteLine(obj.ToString()); 

       } 
1

Myślę, że chcesz coś takiego:

public class Program 
{ 
    public static void PrintProperties<T>(T t) 
    { 
     var properties = t.GetType().GetProperties(); 

     foreach (var property in properties) 
     { 
      var name = property.Name; 
      var value = property.GetValue(t, null); 

      if (property.PropertyType.IsGenericType && property.PropertyType == typeof(IEnumerable<>)) 
      { 
       var formatList = typeof(Program).GetMethod("FormatList", new[] { value.GetType() }); 

       // value.GetType().GetGenericArguments().First() will get you the underlying type of the list, 
       // i.e., the TItemType where the property you are currently 
       // handling is of type IEnumerable<TItemType> 
       formatList.MakeGenericMethod(value.GetType().GetGenericArguments().First()); 

       value = formatList.Invoke(null, new object[] { value }); 

       Console.Out.WriteLine(name + ": " + value); 
      } 
      else 
      { 
       Console.Out.WriteLine(name + ": " + value); 
      } 
     } 
    } 

    public static string FormatList<TPlaceholder>(IEnumerable<TPlaceholder> l) 
    { 
     return string.Join(", ", l); 
    } 
} 

Kod jest niesprawdzone, ale w zasadzie, chcesz walki przeliczalny rodzajów odmiennie w stosunku do wartości skalarnych, więc gdy trafisz coś w rodzaju IEnumerable<TItemType>, można dodzwonić do metody FormatList<TPlaceholder>.

Teraz należy pamiętać, że oryginalne numery T i TItemType niekoniecznie muszą być takie same. Podczas wywoływania FormatList za pomocą refleksji, chcesz związać TPlaceholder z TItemType. Kiedy już to zrobisz, po prostu wywołasz metodę formatowania i przekazujesz jej faktyczne wystąpienie listy, która zwraca ci ciąg znaków. Ten ciąg, który możesz potem wypisać.

Nadzieję, że pomaga.

+0

Moje rozwiązanie jest podobne do zaakceptowanej odpowiedzi, zaakceptuj, że w zaakceptowanej odpowiedzi będziemy polegać na metodzie ToString() dając coś sensownego, podczas gdy w mojej wersji mamy trochę więcej kontroli nad tym, ponieważ możemy rozwiń 'FormatList()', aby zrobić coś bardziej wyrafinowanego. –

0

Pożyczanie na powyższych przykładach, oto moje pełne rozwiązanie. Zostało to przetestowane i obsługuje przekazywanie IEnumerable przez drukowanie właściwości każdego elementu. Nie jest rekursywny, ale można go łatwo dodać.

Należy pamiętać, że wiele z powyższych przykładów ulegnie awarii dzięki indeksowanym właściwościom (na przykład listy). Parameter count mismatch in property.GetValue().

Unika się tego przez filtrowanie właściwości, które mają indeksowane właściwości za pomocą tego bitu LINQ.

Where(x=>!x.GetIndexParameters().Any()) 

Pełny przykład w postaci metody rozszerzenia poniżej.

/// <summary> 
    /// Returns string representation of object property states i.e. Name: Jim, Age: 43 
    /// </summary> 
    public static string GetPropertyStateList(this object obj) 
    { 
     if (obj == null) return "Object null"; 

     var sb = new StringBuilder(); 
     var enumerable = obj as IEnumerable; 

     if (enumerable != null) 
     { 
      foreach (var listitem in enumerable) 
      { 
       sb.AppendLine(); 
       sb.Append(ReadProperties(listitem)); 
      } 
     } 
     else 
     { 
      sb.Append(ReadProperties(obj)); 
     } 

     return sb.ToString(); 
    } 

    private static string ReadProperties(object obj) 
    { 
     var sb = new StringBuilder(); 
     var propertyInfos = obj.GetType().GetProperties().OrderBy(x => x.Name).Where(x=>!x.GetIndexParameters().Any()); 

     foreach (var prop in propertyInfos) 
     { 
      var value = prop.GetValue(obj, null) ?? "(null)"; 
      sb.AppendLine(prop.Name + ": " + value); 
     } 

     return sb.ToString(); 
    } 
Powiązane problemy