2012-02-13 2 views
1

Для целей отладки мне нужно распечатать все общедоступные поля/свойства определенного экземпляра класса. Могу ли я сделать это автоматически? Возможно, есть новая функция в .NET 4.0? Например, WPF DataGrid может сделать что-то подобное.как представлять экземпляр класса как строки без итерации через свойства

Это может быть сделано с помощью руководства по этому вопросу Iterate through class fields and print them, но мне интересно, могу ли я сделать это с использованием какого-то библиотечного метода, а не для кодирования?

I.e. Я хочу, чтобы заменить этот код:

 foreach (PropertyInfo prop in typeof(ServerInfo).GetProperties()) 
     { 
      result += prop.Name + " = " + prop.GetValue(si, null) + "\n"; 
     } 
     foreach (FieldInfo prop in typeof(ServerInfo).GetFields()) 
     { 
      result += prop.Name + " = " + prop.GetValue(si) + "\n"; 
     } 
     return result; 
+0

Доступный код [здесь] (http://stackoverflow.com/a/6745255/870604) действительно прост, почему бы вам не использовать его? – ken2k

+0

Что вам не понравилось в ответе? –

+0

Замените что-нибудь вроде чего? –

ответ

0

Я не уверен, почему вы ищете для лучшего кода. Код у вас есть всего несколько строк и выглядит хорошо для меня.

Если вы хотите изменить код, который вы должны работать с любым типом, то это просто:

string Format(object obj) 
{ 
    Type type = obj.GetType(); 

    foreach (PropertyInfo prop in type.GetProperties()) 
    { 
     result += prop.Name + " = " + prop.GetValue(obj, null) + "\n"; 
    } 
    foreach (FieldInfo field in type.GetFields()) 
    { 
     result += field.Name + " = " + field.GetValue(obj) + "\n"; 
    } 
    return result; 
} 

Другое дело, что можно было бы сделать лучше в этом коде является эффективность: вы должны использовать StringBuilder вместо конкатенирование строк.

0

вы можете переопределить ToString метод пользовательских классов и использовать такой подход, как описано ниже: https://stackoverflow.com/a/6745255/559144

или создать свою собственную библиотеку/помощника, где вы положили код по ссылке и для всех классов, которые вы хотите использовать, просто поместите вызов вспомогательному методу из переопределения ToString.

Не уверен, что вы подразумеваете под WPF. Datagrid может это сделать, вы уверены, что не говорите о визуализаторе Visual Studio Debugger DataSet?

0

Цитируется Thomas:

User user = ... 
foreach(PropertyInfo prop in typeof(User).GetProperties()) 
{ 
    Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(user, null)); 
} 
+0

, он работает, но не включает в себя поля и выглядит нечетным – javapowered

0

Если вы стремитесь к простой список свойств, которые будут отображаться с WPF, может быть, это помогло бы с помощью ListBox с ItemsSource «DataBound» к объекту. Чтобы получить список свойств в виде строк из этого объекта, используйте некоторую реализацию IValueConverter, которая считывает свойства, как описано в последних нескольких комментариях, и помещает их в IEnumerable.

Когда вы обмениваетесь объектом в DataBinding, новый объект отображается немедленно.

+0

Я просто хочу преобразовать Object в String. Я говорил о WPF, потому что WPF может это сделать. – javapowered

0

Нет лучшего способа, чем код, который вы уже написали, если вы действительно настроены на все свойства и поля. Вы можете написать метод расширения и объединить его в пространство имен System, таким образом оно появится в каждом экземпляре любого типа; Я хотел бы также серьезно рассмотреть вопрос об использовании StringBuilder, AppendLine и string.Format:

namespace System 
{ 
    public static class MyExtensions 
    { 
    public static string Report<T>(this T instance) 
    { 
     StringBuilder sb = new StringBuilder(); 
     foreach (PropertyInfo prop in typeof(T).GetProperties()) 
     { 
     sb.AppendLine(
      string.Format("{0} = {1}", prop.Name, prop.GetValue(si, null)); 
     } 
     foreach (FieldInfo prop in typeof(T).GetFields()) 
     { 
     sb.AppendLine(
      string.Format("{0} = {1}", prop.Name, prop.GetValue(si, null)); 
     } 
     return sb.ToString(); 
    } 
    } 
} 

После того, как вы написали это, вы можете просто сделать:

var instance = new ServerInfo(); 
var report = instance.Report(); 

Проблема с этим состоит в том, что он не обрабатывает ситуация, когда наилучшим представлением типа на самом деле является только вызов ToString, например int или string (строка особенно, поскольку этот код просто выводит элемент Length).

Вы упоминаете DataGrid WPF - это стоит отметить, что это не использует отражения напрямую, вместо этого он использует System.ComponentModel.TypeDescriptor класса - который является расширяемым и использует механизм TypeConverter для поддержки преобразования в/из строк (намного лучше, чем просто полагаться на ToString).

Однако он не содержит полей в метаданных, которые он производит; которые вы явно хотите.

В качестве заключительного замечания я бы сказал, что такого рода вещи не должны использоваться много в программах; потому что очень редко этот уровень детализации имеет значение.Тогда возникает вопрос, насколько глубоко ваш отчет должен идти; для каждого члена, если вы на самом деле не используете снова Report (в этом случае вам нужно либо опоздать на поздний срок, либо просто написать его вместо object)? Но тогда у вас есть неприятный код для проверки типов, которые должны быть сведены в или только ToString 'd. И если вы начнете делать это, вам также необходимо позаботиться о том, чтобы не переписываться через перекрестные ссылки; в противном случае метод отчета может просто заблокировать ваше приложение.

Я хотел бы предложить вместо этого интерфейс лучше:

public interface IReportable 
{ 
    void Report(StringBuilder target); 
} 

Реализация интерфейс, то ограничивается только типами, которые вам действительно нужны, чтобы сообщить о; и вы можете использовать метод расширения выше или один из них как реализацию по умолчанию для большинства ваших типов. Тем не менее, важно, что тип может предоставить свои собственные, если это необходимо.

0

Вы можете написать методы расширения для Type класса:

public static class TypeExtensions 
{ 
    public static List<string> GetFieldsAndPropertiesAsString(this Type type) 
    { 
     return new List<string>(type.GetFieldsAsString().Union(type.GetPropertiesAsString())); 
    } 

    public static IEnumerable<string> GetFieldsAsString(this Type type) 
    { 
     // Modify BindingFlags to get what you want (instance only, private/public...) 
     foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) 
     { 
      yield return field.Name; 
     } 
    } 

    public static IEnumerable<string> GetPropertiesAsString(this Type type) 
    { 
     // Modify BindingFlags to get what you want (instance only, private/public...) 
     foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) 
     { 
      yield return prop.Name; 
     } 
    } 
} 

Затем вызовите его с помощью:

foreach (string zz in typeof(MyClass).GetFieldsAndPropertiesAsString()) 
{ 
    Console.WriteLine(zz); 
} 
Смежные вопросы