将Json中的List<string>反序列化为List<object>

3
我有以下 JSON 字符串作为我的问题的示例:
{
    "Code": "Admin",
    "Groups":
    [
        "Administrator",
        "Superuser",
        "User"
    ]
}

也就是说,我有一个叫做“User”的类,其中的代码如下...
[JsonObject(MemberSerialization.OptIn)]
public class User
{
    public User (string code)
    {
        this.Code = code;
    }

    [JsonProperty]
    public string Code { get; set; }

    [JsonProperty("Groups")]
    private List<UserGroup> groups;
    public List<UserGroup> Groups
    {
       if (groups == null)
           groups = new List<UserGroup>();
       return groups;
    }
}

"...还有一个名为UserGroup的类,对于这个例子,只有这几行代码:"
public class UserGroup
{
    public UserGroup (string code)
    {
        this.Code = code;

        // Some code to fill all the other properties, just by knowing the code.
    }

    public string Code { get; set; }

    // More properties
}

现在,我想要的是,上面显示的JSON字符串将被反序列化为一个User实例,并且 "Groups"数组中的所有字符串都应该被反序列化为一个List<UserGroup>,其中包含每个字符串的实例。同样 - 另一个方向 - 应该将一个User序列化为仅包含所包含的UserGroups的Code属性的JSON字符串。
我不会正常地反序列化,而是创建一个User实例并使用这段代码填充它...
Newtonsoft.Json.JsonConvert.PopulateObject(jsonString, myUserInstance);

“…但如果我使用上述显示的JSON字符串运行代码,我只会得到以下异常:”
Newtonsoft.Json.JsonSerializationException: 'Error converting value "Administrator" to type 'UserGroup'.

我的最终要求是,如果我序列化User,我希望UserGroup被序列化为一个字符串数组。当我将UserGroup作为根对象单独序列化时,它应该正常序列化(包括所有属性)。 (为了比较,在Json.Net: Serialize/Deserialize property as a value, not as an object中,该对象在所有情况下都被序列化为字符串。)

2
两个选项。创建一个自定义的JsonConverter来处理转换,或者向类添加隐式操作符以知道如何从字符串进行转换。 - Nkosi
我需要创建一个从String到UserGroup以及从UserGroup到String的JsonConverter,还是从String到List<UserGroup>的JsonConverter? 另外,什么是添加隐式操作符的意思? - Christoph Mett
只是好奇,为什么不直接使用这个呢? [JsonProperty("Groups")] public string[] Groups { get; set; } - Chandra Sekhar V
因为UserGroup不仅包含Code属性。这只是为了更容易理解。 - Christoph Mett
看起来是 Json.Net: Serialize/Deserialize property as a value, not as an object 的重复问题。这个回答解决了你的问题吗?还是你需要更具体的内容? - dbc
显示剩余2条评论
2个回答

2

您需要编写一个转换器来处理 UserGroup

这里是一个简单的转换器,基于问题描述而来。

public class UserGroupJsonConverter : JsonConverter {

    public override bool CanConvert(Type objectType) {
        return typeof(UserGroup) == objectType;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        return new UserGroup((string)reader.Value);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        writer.WriteValue(((UserGroup)value).Code);
    }
}

然后通过设置JsonProperty属性的ItemConverterType来使User了解转换器的存在。

[JsonObject(MemberSerialization.OptIn)]
public class User {
    public User(string code) {
        this.Code = code;
    }

    [JsonProperty]
    public string Code { get; set; }

    private List<UserGroup> groups;
    [JsonProperty("Groups", ItemConverterType = typeof(UserGroupJsonConverter))]
    public List<UserGroup> Groups {
        get {
            if (groups == null)
                groups = new List<UserGroup>();
            return groups;
        }
    }
}

这将允许在示例中使用JSON。
{
    "Code": "Admin",
    "Groups":
    [
        "Administrator",
        "Superuser",
        "User"
    ]
}

以期望的方式反序列化

var user = JsonConvert.DeserializeObject<User>(json);

并且需要按照相同的格式进行反序列化。

var json = JsonConvert.SerializeObject(user);

如果我这样做,例如不想序列化我的用户,而是可能序列化用户组本身,它不会使用此转换器(如果我没有告诉它),但会正常序列化它,包括属性名称等,对吗? - Christoph Mett
@ChristophMett,是的。在上面的例子中,属性仅应用于User对象上的Groups属性。如果您只想序列化UserGroup对象本身,则不会应用转换器。 - Nkosi

0

管理员是一个字符串,UserGroup是一个对象,因此这是一种类型不匹配。您代码中描述的情况的有效JSON如下:

{
    "Code": "Admin",
    "Groups":
    [
        {
            "Code":"Administrator"
        },
        {
            "Code":"Superuser"
        },
        {
            "Code":"User"
        }
    ]
}

一般来说,这是完全正确的,但在我的示例中,我不想在JSON字符串中保存整个UserGroup对象结构,而只想保存代码。 代码属性足以让我的代码获取整个UserGroup实例。因此,为了不保存冗余数据(我知道,这是JSON的一个几乎必要的部分),我只想在JSON中保存代码属性中的字符串,并且希望反序列化从代码字符串中获取整个UserGroup实例。 - Christoph Mett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接