Как рекурсивно печатать значения свойств объекта с помощью отражения

Чтобы помочь в отладке некоторого кода, над которым я работаю, я начал писать метод для рекурсивной печати имен и значений свойств объекта. Однако большинство объектов содержат вложенные типы, и я хотел бы также печатать их имена и значения, но только для типов, которые я определил.

Вот контур того, что у меня есть до сих пор:

public void PrintProperties(object obj)
{
    if (obj == null)
        return;

    Propertyinfo[] properties = obj.GetType().GetProperties();

    foreach (PropertyInfo property in properties)
    {
        if ([property is a type I have defined])
        {
            PrintProperties([instance of property type]);
        }
        else
        {
            Console.WriteLine("{0}: {1}", property.Name, property.GetValue(obj, null));
        }
    }

Части между фигурными скобками - это то место, где я не уверен.

Любая помощь будет принята с благодарностью.

Ответ 1

Приведенный ниже код пытается это сделать. Для "type я defined" я решил посмотреть типы в той же сборке, что и те, у которых свойства печатаются, но вам нужно будет обновить логику, если ваши типы определены в нескольких сборках.

public void PrintProperties(object obj)
{
    PrintProperties(obj, 0);
}
public void PrintProperties(object obj, int indent)
{
    if (obj == null) return;
    string indentString = new string(' ', indent);
    Type objType = obj.GetType();
    PropertyInfo[] properties = objType.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object propValue = property.GetValue(obj, null);
        if (property.PropertyType.Assembly == objType.Assembly && !property.PropertyType.IsEnum)
        {
            Console.WriteLine("{0}{1}:", indentString, property.Name);
            PrintProperties(propValue, indent + 2);
        }
        else
        {
            Console.WriteLine("{0}{1}: {2}", indentString, property.Name, propValue);
        }
    }
}

Ответ 2

Есть ли какая-то конкретная причина, по которой вы хотите использовать отражение? Вместо этого вы можете использовать JavaScriptSerializer следующим образом:

var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string json = serializer.Serialize(obj);
Console.WriteLine(json);

Он будет рекурсивно включать все свойства в строку и исключить исключение в случае появления круговой ссылки.

Ответ 3

Кредитное плечо из Ответ Леонида, ниже код - это то, что я использовал для создания читаемого дампа Json любого объекта. Он игнорирует пустое поле и добавляет отступы для лучшего обзора (особенно хорошо для SOAP-объектов).

public static string SerializeToLogJson(this object obj)
        {
            try
            {
                var json = JsonConvert.SerializeObject(obj,
                    Newtonsoft.Json.Formatting.None, 
                    new JsonSerializerSettings { 
                        NullValueHandling = NullValueHandling.Ignore,
                        Formatting = Formatting.Indented
                    });
                return json;
            }
            catch (Exception e)
            {
                log.ErrorFormat(e.Message, e);
                return "Cannot serialize: " + e.Message;
            }
        }

Ответ 4

Newtonsoft библиотека предоставляет очень простые функции для сериализации любого объекта в JSON. Это гораздо более простое решение.

Newtonsoft.Json.JsonConvert.SerializeObject(objToSerialize);

например:

dynamic obj = new { x = 1, y = 2, z = "abc" };
string json = JsonConvert.SerializeObject(obj);
//'json' string value: {"x":1,"y":2,"z":"abc"}