将具有嵌套属性的对象打印为以逗号分隔的键值对字符串

时间:2018-10-12 13:39:52

标签: c# .net reflection json.net

我有一个Person班:

public class Person
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
}

最终,我想将一个Person实例打印为JSON,但我希望它是一个很大的键值对字符串,例如:

"Name:John,Surname:Doe,Line1:Infinite Loop,Line2:California"

请注意,在上面的示例中,我摆脱了实际的类名(即,它打印出Line1而不是Address.Line1)-我只关心所有名称/值对。

因此最终结果将是Person s的数组:

"persons":[
    "Name:John,Surname:Doe,Line1:Infinite Loop 1,Line2:California",            
    "Name:Jane,Surname:Doe,Line1:Infinite Loop 2,Line2:California"
]

作为起点,我尝试使用反射:

void Main()
{
    var persons = new List<Person>();
    persons.Add(new Person
    {
        Name = "John",
        Surname = "Doe",
        Address = new Address
        {
            Line1 = "Infinite Loop",
            Line2 = "California"                
        }
    });

    foreach(var person in persons)
    {
        var properties = new List<string>();
        foreach(var property in person.GetType().GetProperties())
        {
            properties.Add($"{property.Name}:{property.GetValue(person, null)}");
        }
        Console.WriteLine(string.Join(",", properties));
    }
}

但是我在LINQPad中得到以下输出:

Name:John,Surname:Doe,Address:UserQuery+Address

我假设Address未被正确迭代,因为它是Person中的嵌套对象。即使这样,这也不是最干净/最有效的方法。

4 个答案:

答案 0 :(得分:2)

您可以使用自定义JsonConverter来做到这一点,就像这样:

class PersonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Person);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var pairs = JObject.FromObject(value)
            .Descendants()
            .OfType<JProperty>()
            .Where(p => p.Value is JValue)
            .Select(p => p.Name + ":" + p.Value);
        writer.WriteValue(string.Join(",", pairs));
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

然后通过将转换器传递到JsonConvert.SerializeObject来使用它,如下所示:

string json = JsonConvert.SerializeObject(obj, Formatting.Indented, new PersonConverter());

这是一个有效的演示:https://dotnetfiddle.net/L4YDsm

答案 1 :(得分:1)

向您的课程添加ToString覆盖并以JSON形式返回字符串的集合。

public class Person
{
  public string Name { get; set; }
  public string Surname { get; set; }
  public Address Address { get; set; }
  public override string ToString()
  {
    return $"Name:{Name},Surname:{Surname},Line1:{Address?.Line1},Line2:{Address?.Line2}";
  }
}

答案 2 :(得分:1)

您必须以某种方式实现反射,使其可以更深入地进入对象的结构,以便执行所需的操作。这是对您提供的代码的简单递归和通用适应。

public static string GetRecursivePropertyValues(object obj)
{
    var properties = new List<string>();
    foreach (var property in obj.GetType().GetProperties())
    {
        object currentPropertyValue = property.GetValue(obj);
        if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(string))
            properties.Add($"{property.Name}:{currentPropertyValue}");
        else
        {
            var subProperties = GetRecursivePropertyValues(currentPropertyValue);
            properties.Add(subProperties);
        }
    }
    return string.Join(";", properties);
}

此实现首先验证是否用基本类型或string(在C#中不视为基本类型)定义每个属性,并在这种情况下正常打印它们。否则,如果类型很复杂(例如,将其声明为Address实例),它将以递归方式检索复杂对象的属性,并将其添加到结果字符串中。

您可以这样称呼它:

string propertiesStr = GetRecursivePropertyValues(person);

编辑:代码现在仅根据OP的要求展平对象(先前的代码示例使用了一些粗糙的JSON格式)。

答案 3 :(得分:1)

使用Newtonsoft.json

https://www.newtonsoft.com/json/help/html/SerializingJSON.htm

检查上面的链接...它将告诉您如何将对象序列化为json,需要注意的重要一点是,您需要将所有项添加到列表中,然后将列表序列化为json以达到预期的效果

Product product = new Product();

product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

有例子:

string output = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "ExpiryDate": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}