继承Dictionary时的序列化

Serialization when inheriting from Dictionary

我正在使用 System.Web.Script.Serialization.JavaScriptSerializer 序列化/反序列化扩展字典的 class。

问题是,我的自定义属性没有被序列化。这是我的 class:

public class Test : Dictionary<string, object> {
    public ushort Id { get; set; }
    public string Name { get; set; }
}

还有我的代码:

var jss = new JavaScriptSerializer();

var test = new Test {
    Id = 123,
    Name = "test"
};

var json = jss.Serialize(test);

json 中的结果为空 json {}

我不想依赖 Newtonsoft 或 JSON.Net 或任何其他库。

附加信息

我刚刚注意到一些,嗯,同时使用 dynamicobject 时的特点:

这可能会导致使用 属性 索引器的 class 中出现强制转换异常(如已接受的答案中所建议),例如:

public class Test : Dictionary<string, dynamic> {
    public ushort Id { get => this[nameof(Id)]; set => this[nameof(Id)] = value; }
}

Id 属性 getter 将尝试将 int 隐式转换为 ushort,但会失败。

附加信息 2

我刚刚发现 Newtonsoft 有很多奇怪的行为:

我添加了这些属性来解决 'long to ushort' 问题:

[JsonObject(MemberSerialization.OptIn)]
public class Test : Dictionary<string, dynamic> {
    [JsonProperty]
    public ushort Id { get => this[nameof(Id)]; set => this[nameof(Id)] = value; }
}

以上有效!但是当 属性 是引用类型时:

[JsonObject(MemberSerialization.OptIn)]
public class Test : Dictionary<string, dynamic> {
    [JsonProperty]
    public ushort Id { get => this[nameof(Id)]; set => this[nameof(Id)] = value; }
    [JsonProperty]
    public Test Child { get => this[nameof(Child)]; set => this[nameof(Child)] = value; }
}

它在序列化之前尝试获取 属性,结果是 'key not found exception'。我不明白为什么它仅在引用类型时才尝试获取 属性,这对我来说似乎是个错误...

所以你必须这样做:

public Test Child { get => this.ContainsKey(index) ? this[nameof(Child)] : null; ... }

只是总结评论:

要使用组合,您只需像这样修改您的测试对象:

public class Test
{
    public ushort Id { get; set; }
    public string Name { get; set; }
    public Dictionary<string, object> Items { get; set; } = new Dictionary<string, object> {};
}

那么下面的代码就可以正常工作了:

var jss = new JavaScriptSerializer();
var test = new Test
{
    Id = 123,
    Name = "test",
};
test.Items.Add("A", 1);
var json = jss.Serialize(test);

输出只是:

{"Id":123,"Name":"test","Items":{"A":1}}

更新:属性 索引器

您可以将默认索引器添加到您的 class 以便以下代码可以工作:

test["A"] = 1;
var result = test["A"];

这是为默认索引器添加的代码:

public object this[string key]
{
    get { return this.Items[key]; }
    set { this.Items[key] = value; }
}

我想你可以将其扩展到实现 IDictionary,但我认为只使用合成应该是最简单的。