解析json时如何将字符串转换为集合



我试图访问一个API,并得到下面的响应体与邮差:

{
"Name": "wangxiaoer",
"Created": "2018-01-26T01:28:19.0388857Z",
"Modified": "2019-06-18T03:46:52.4350569Z",
"AdminSecurityGroups": "mhanch;sastrys;vinala;vballa",
"DeveloperOwner": "sastrys;vballa",
"ProgramManagerOwner": "sastrys",
"Comments": null
}

我使用了下面的代码:

var content = await httpResponse.Content.ReadAsStringAsync();

获取响应体

我想将这个内容反序列化为一个自定义对象,如下所示:

class MyObject
{
public string Name{get;set}
[JsonProperty(PropertyName = "AdminSecurityGroups")]
public List<String> Admins { get; set; }
[JsonProperty(PropertyName = "DeveloperOwner")]
public List<String> DevOwner { get; set; }
[JsonProperty(PropertyName = "ProgramManagerOwner")]
public List<String> PMOwner { get; set; }
}

由于响应内容为我提供了由AdminSecurityGroups, DeveloperOwner, ProgramManagerOwner的';'分割的多个人的别名组成的每个字符串,因此最好将每个字符串转换为列表,以便以后重用它。我试图在对象中定义一个列表,而不是使用String来存储这些部分,但是当我使用

MyObject my = JsonConvert.DeserializeObject<MyObject>(content);

抛出异常。当使用c#解析json字符串时,是否有方法实现将字符串转换为列表?例如:

"AdminSecurityGroups": "mhanch;sastrys;vinala;vballa"

通过分裂包含4个人;当获得响应字符串时。需要将其解析为列表

您可以通过多种方式做到这一点,

  1. 规范化json, json有数组....

  2. 反序列化为字符串,然后使用另一个属性拆分它,或者映射到另一个属性。

  3. 只需使用转换器,它是为这种情况构建的

Json。

public class MyObject
{
public string Name{get; set; }
[JsonProperty( "AdminSecurityGroups")]
[JsonConverter(typeof(MyFunkConverter))]
public List<string> Admins { get; set; }
[JsonProperty( "DeveloperOwner")] 
[JsonConverter(typeof(MyFunkConverter))]
public List<string> DevOwner { get; set; }
[JsonProperty( "ProgramManagerOwner")]
[JsonConverter(typeof(MyFunkConverter))]
public List<string> PMOwner { get; set; }
}
public class MyFunkConverter : JsonConverter<List<string>>
{
public override void WriteJson(JsonWriter writer, List<string> value, JsonSerializer serializer)
=> throw new NotImplementedException(); 
public override List<string> ReadJson(JsonReader reader, Type objectType, List<string> existingValue, bool hasExistingValue, JsonSerializer serializer) =>
reader.Value.ToString().Split(';').ToList();
}
...
var result =  JsonConvert.DeserializeObject<MyObject>(input); 

文本。Json

public class MyObject
{
public string Name{get; set; }
[JsonPropertyName("AdminSecurityGroups")]
[JsonConverter(typeof(MyFunkConverter))]
public List<string> Admins { get; set; }
[JsonPropertyName("DeveloperOwner")]
[JsonConverter(typeof(MyFunkConverter))]
public List<string> DevOwner { get; set; }
[JsonPropertyName( "ProgramManagerOwner")]
[JsonConverter(typeof(MyFunkConverter))]
public List<string> PMOwner { get; set; }
}
public class MyFunkConverter : System.Text.Json.Serialization.JsonConverter<List<string>>
{
public override List<string>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 
=> reader.GetString().Split(';').ToList();
public override void Write(Utf8JsonWriter writer, List<string> value, JsonSerializerOptions options) 
=> throw new NotImplementedException();
}
...
var result =  JsonSerializer.Deserialize<MyObject>(input);

这里有一个更简单的方法。只需将JSON反序列化为对象,并通过只读属性将这些字符串作为集合公开。

这样做的优点是将原始(分号完整的)字符串公开为属性(如果有人想看到它们)。事实上,那些我使用你的属性名称,我可能会重命名AdminsDeveloperOwnerRawPmOwnerAdminSecurityGroupsRawDeveloperOwnerRawProgramManagerOwnerRaw如果这是我的代码。

首先扩展您的MyObject类(我给了它一个更具描述性的名称):

public class JsonStringToArrayObject
{
public string Name { get; set; }
[JsonProperty(PropertyName = "AdminSecurityGroups")]
public string Admins { get; set; }
[JsonProperty(PropertyName = "DeveloperOwner")]
public string DevOwner { get; set; }
[JsonProperty(PropertyName = "ProgramManagerOwner")]
public string PmOwner { get; set; }
private List<string> _adminSecurityGroups = null;
private List<string> _developerOwner = null;
private List<string> _programManagerOwner = null;
[JsonIgnore]
public IEnumerable<string> AdminSecurityGroups
{
get
{
if (_adminSecurityGroups == null && !string.IsNullOrWhiteSpace(Admins))
{
_adminSecurityGroups = Admins.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
return _adminSecurityGroups;
}
}
[JsonIgnore]
public IEnumerable<string> DeveloperOwner
{
get
{
if (_developerOwner == null && !string.IsNullOrWhiteSpace(DevOwner))
{
_developerOwner = DevOwner.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
return _developerOwner;
}
}
[JsonIgnore]
public IEnumerable<string> ProgramManagerOwner
{
get
{
if (_programManagerOwner == null && !string.IsNullOrWhiteSpace(PmOwner))
{
_programManagerOwner = PmOwner.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
return _programManagerOwner;
}
}
}

json公开的属性是相同的。但是,我添加了只读属性,将分号分隔的字符串公开为数组。这些getter的代码重复了三次,您可能希望将其重构为一个小的worker函数。

执行此操作的代码很简单,首先是JSON(我使用单引号-在c#中更容易):

private const string theJson = @"
{
'Name': 'wangxiaoer',
'Created': '2018-01-26T01:28:19.0388857Z',
'Modified': '2019-06-18T03:46:52.4350569Z',
'AdminSecurityGroups': 'mhanch;sastrys;vinala;vballa',
'DeveloperOwner': 'sastrys;vballa',
'ProgramManagerOwner': 'sastrys',
'Comments': null
}";

然后是这个:

var jsonStringToArrayObject = JsonConvert.DeserializeObject<JsonStringToArrayObject>(theJson);
在类似的代码执行之后,我可以在调试器中看到以下内容:
-   AdminSecurityGroups Count = 4   
[0] "mhanch"    string
[1] "sastrys"   string
[2] "vinala"    string
[3] "vballa"    string

-   DeveloperOwner  Count = 2   
[0] "sastrys"   string
[1] "vballa"    string

-   ProgramManagerOwner Count = 1   
[0] "sastrys"   string

那个重复的代码把我逼疯了。所以我做了一点重构,将这个私有方法添加到JsonStringToArrayObject:
private IEnumerable<string> GetterImplementation(ref List<string> privateField, string source)
{
if (privateField == null && !string.IsNullOrWhiteSpace(source))
{
privateField = source.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
return privateField;
}

那么这三个只读属性的结尾是:

[JsonIgnore]
public IEnumerable<string> AdminSecurityGroups => GetterImplementation(ref _adminSecurityGroups, Admins);
[JsonIgnore]
public IEnumerable<string> DeveloperOwner => GetterImplementation(ref _developerOwner, DevOwner);
[JsonIgnore]
public IEnumerable<string> ProgramManagerOwner => GetterImplementation(ref _programManagerOwner, PmOwner);

和其他东西都是一样的

最新更新