为什么JavaScriptSerializer无法序列化内部属性?

3

我一直在序列化自定义类型,该类型具有一些内部属性。但是,在使用 System.Web.Script.Serialization.JavaScriptSerializerserialize方法进行序列化时,似乎不会序列化内部属性(因为它在序列化字符串中跳过了内部属性)。从下面的代码和输出可以很容易地理解:

public class MyClass
{
    public string Property1 { get; set; }

    internal string Property2 { get; set; }

    public string Property3 { get; set; }
}

JavaScriptSerializer mySerializer = new JavaScriptSerializer();
string jsonString = mySerializer.Serialize(new MyClass()
{
            Property1 = "One",
            Property2 = "Twp",
            Property3 = "Three"
});

jsonString 的值如下:

{"Property1":"One","Property3":"Three"}

在输出中,您可以看到序列化字符串没有 Property2,这是一个内部属性。是否有逻辑原因不支持在序列化中使用内部属性?
如何解决序列化内部属性的问题(除了将内部属性更改为公共修饰符)?

在将数据发送到完全不同的位置(序列化)的过程中,默认情况下包含被标记为程序集外部不可访问的数据块(internal),这似乎是违反直觉的。 - Will Ray
@Will:很难理解,为什么微软在序列化中考虑了跨程序集问题,因为很容易看到序列化经常在同一程序集中执行。 - Akash KC
2个回答

4

System.Web.Script.Serialization.JavaScriptSerializer中不支持此功能。

我建议您切换到Json.NET。在这种情况下,您只需要使用json属性属性标记内部属性,Json.NET序列化器就会将其捕获。

[Newtonsoft.Json.JsonProperty]
internal string Property2 { get; set; }

值得注意的是,Json.NET比DataContractJsonSerializer快50%,比JavaScriptSerializer快250%,并且具有更多的配置选项,目前是微软.NET的默认选择。
根据您在评论中的要求,如果使用DataContractJsonSerializer,使用.NET FCL库也可以实现此功能,尽管这会带来自己的一套痛苦,因为需要分别对每个类和属性标记[DataContract]和[DataMember]。
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

var instance = new MyClass {
        Property1 = "One",
        Property2 = "Twp",
        Property3 = "Three"
};

var ser = new DataContractJsonSerializer(instance.GetType());

using (MemoryStream ms = new MemoryStream())
{
    ser.WriteObject(ms, instance);
    string jsonData = Encoding.Default.GetString(ms.ToArray());
}

[DataContract]
public class MyClass
{
    [DataMember]
    public string Property1 { get; set; }
    [DataMember]
    internal string Property2 { get; set; }
    [DataMember]
    public string Property3 { get; set; }
}

这将正确输出。
{"Property1":"One","Property2":"Twp","Property3":"Three"}

尽管我个人认为您对于零价值的坚持过于教条,并且给自己带来了很多痛苦。但我仍然强烈建议您切换到更现代的序列化工具。

我只是好奇为什么System.Web.Script.Serialization.JavaScriptSerializer不支持它。有没有不支持它的原因?是的,我可以按照您指定的使用Newtonsoft来完成,但对于简单的序列化/反序列化,我认为JavaScriptSerializer应该也可以胜任。 - Akash KC
1
因为当微软编写它时,他们没有考虑到这一点。你必须问写序列化器类的人:)。也就是说,现在没有理由再使用JavaScriptSerializer了。它已经过时、速度慢、效率低下且古怪。你应该转换成更现代的序列化器。 - David L
.NET FCL本身是否有其他方法来序列化/反序列化内部属性? - Akash KC
事实上,我正在开发的应用程序较小(以大小为标准,我的应用程序:10KB,Newtonsoft:475KB),因此我犹豫是否使用第三方库(Newtonsoft)来完成简单的序列化工作。这个问题只是出于我的好奇心,否则你的答案真的很棒。 - Akash KC
如果可能的话,我建议在这种情况下使用一个更小的序列化器。像 https://github.com/kevin-montrose/Jil 这样的东西可能适合你,尽管它可能仍然太大了。听起来你关心的是库的总大小而不是速度,这意味着你可能只能使用DataContractJsonSerializer。 - David L
感谢您的努力。我一定会研究一下 Jil 库,这是我第一次听说它 :( - Akash KC

1

JavaScriptSerializer的文档内容较为简略,关于该类型如何处理访问修饰符的问题我没有找到任何信息。

internal会将Property2从程序集外部的类型中隐藏,因此我认为JavaScriptSerializer中有一些代码会询问“我可以看到这个对象上的哪些属性?”

这是一个棘手的问题,正如你所见,更健壮的序列化系统会询问文档更详细的问题:“这个对象上的哪些属性带有序列化提示?”

参见JSON.net(JavaScriptSerializer文档推荐)和DataContractJsonSerializer


.NET FCL本身是否有其他方法来序列化/反序列化内部属性? - Akash KC
DataContractJsonSerializer 应该尊重所有标记有 DataMember 的属性,无论其访问修饰符如何,如果我没记错的话。 - Matt Stephenson
1
此外,@LolCoder아카쉬,我理解坚持使用基础类的想法。我曾在一些情况下工作过,需要在生产环境中安装库所需的投入很快就超过了从基础类重新发明轮子的投入。 - Matt Stephenson

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