繁体   English   中英

DataContractJsonSerializer; 可通过.NET调用但不能通过Mono调用的ISerializable GetObjectData

[英]DataContractJsonSerializer ; ISerializable GetObjectData called with .NET but not with mono

以下是我要完成的工作的简化示例。

我有一个类DoNotSerializeMe,它是外部库的一部分,不能序列化。

using System;

namespace CustomJsonSerialization
{
    public class DoNotSerializeMe
    {
        public string WhyAmIHere;

        public DoNotSerializeMe(string mystring)
        {
            Console.WriteLine("    In DoNotSerializeMe constructor.");
            WhyAmIHere = "( constructed with " + mystring + " )";
        }
    }
}

我也有一个SerializeMe类,该类具有DoNotSerializeMe类型的成员。 我可以使此类实现ISerializable,并通过提取数据和调用构造函数来解决DoNotSerializeMe无法序列化的问题。

using System.Runtime.Serialization;
using System.Security.Permissions;

namespace CustomJsonSerialization
{
    [System.Serializable]
    public class SerializeMe : ISerializable
    {
        public DoNotSerializeMe SerializeMeThroughISerializable;

        public SerializeMe(string mystring)
        {
            SerializeMeThroughISerializable = new DoNotSerializeMe(mystring);
        }

        protected SerializeMe(SerializationInfo info, StreamingContext context)
        {
            System.Console.WriteLine("    In SerializeMe constructor (ISerializable)");
            SerializeMeThroughISerializable = new DoNotSerializeMe(info.GetString("SerializeMeThroughISerializable"));
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            System.Console.WriteLine("    In SerializeMe.GetObjectData()");
            info.AddValue("SerializeMeThroughISerializable", 
                    "( deserialized through getObjectData " + 
                    SerializeMeThroughISerializable.WhyAmIHere + " )");
        }
    }
}

下面是一个序列化和反序列化对象的简短程序:

using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

namespace CustomJsonSerialization
{
    public class Program
    {
        public static void Main(string[] args)
        {
            SerializeMe serializeme = new SerializeMe("initial");

            Console.WriteLine("I created it: {0}", serializeme.SerializeMeThroughISerializable.WhyAmIHere);
            Console.WriteLine();

            MemoryStream memstream = new MemoryStream();
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SerializeMe));
            serializer.WriteObject(memstream, serializeme);

            Console.WriteLine("I serialized it: {0}", serializeme.SerializeMeThroughISerializable.WhyAmIHere);
            Console.WriteLine();

            Console.WriteLine("Json:");
            Console.WriteLine(Encoding.ASCII.GetString(memstream.ToArray()));
            Console.WriteLine();

            memstream.Seek(0, SeekOrigin.Begin);
            SerializeMe anotherSerializeMe = (SerializeMe)serializer.ReadObject(memstream);
            Console.WriteLine("I deserialized it: {0}", anotherSerializeMe.SerializeMeThroughISerializable.WhyAmIHere);

        }
    }
}

通过.NET(4.5)运行时,得到以下信息:

    In DoNotSerializeMe constructor.
I created it: ( constructed with initial )

    In SerializeMe.GetObjectData()
I serialized it: ( constructed with initial )

Json:
{"SerializeMeThroughISerializable":"( deserialized through getObjectData ( constructed with initial ) )"}

    In SerializeMe constructor (ISerializable)
    In DoNotSerializeMe constructor.
I deserialized it: ( constructed with ( deserialized through getObjectData ( constructed with initial ) ) )

当进行序列化/反序列化时(如预期的那样),序列化程序调用了ISerializable结构和GetObjectData。 我从不直接序列化或反序列化DoNotSerializeMe对象。

但是,当通过mono运行相同的构建时(尝试过3.10.0和4.0.2),我得到以下信息:在DoNotSerializeMe构造函数中。 我创建了它:(用initial构造)

I serialized it: ( constructed with initial )

Json:
{"SerializeMeThroughISerializable":{"WhyAmIHere":"( constructed with initial )"}}

I deserialized it: ( constructed with initial )

显然,如果DoNotSerializeMe确实不可序列化,则将导致错误。

有没有不用Json.NET就能解决此问题的优雅方法? 我不确定为什么单声道与.NET的行为方式不同。

我将建议一种替代方法:使用替代数据传输类型来序列化您的DoNotSerializeMe类。 一种方法是使用Data Contract Surrogates 但是单声道支持数据合同替代吗? 当前版本的源代码表明它们是,但是此版本将其显示为[MonoTODO] ,因此我不能保证您的mono版本具有DataContractJsonSerializer.DataContractSurrogate的有效实现。

但是,手动代理属性将始终起作用。 例如,即使不能直接序列化以下SerializeMe类型的DoNotSerializeMe成员,也可以对其进行序列化和序列化:

public class DoNotSerializeMe
{
    public readonly string WhyAmIHere;
    readonly bool ProperlyConstructed; // data contract serializer does not call the constructor

    public DoNotSerializeMe(string mystring)
    {
        Console.WriteLine(string.Format("    In DoNotSerializeMe constructor, mystring = \"{0}\"", mystring));
        WhyAmIHere = mystring;
        ProperlyConstructed = true;
    }

    public void Validate()
    {
        if (!ProperlyConstructed)
            throw new InvalidOperationException("!ProperlyConstructed");
    }
}

public class SerializeMe
{
    [IgnoreDataMember]
    public DoNotSerializeMe CannotBeSerializedDirectly;

    public DoNotSerializeMeSurrogate DoNotSerializeMeSurrogate
    {
        get
        {
            if (CannotBeSerializedDirectly == null)
                return null;
            return new DoNotSerializeMeSurrogate { WhyAmIHereSurrogate = CannotBeSerializedDirectly.WhyAmIHere };
        }
        set
        {
            if (value == null)
                CannotBeSerializedDirectly = null;
            else
                CannotBeSerializedDirectly = new DoNotSerializeMe(value.WhyAmIHereSurrogate);
        }
    }

    public string SomeOtherField { get; set; }
}

public class DoNotSerializeMeSurrogate
{
    public string WhyAmIHereSurrogate { get; set; }
}

使用此方法看起来比实现ISerializable更简单,因为除CannotBeSerializedDirectly以外的所有成员都将继续自动进行序列化。 注意[IgnoreDataMember]的使用。 这样可以防止CannotBeSerializedDirectly成员包含在该类的隐式数据协定中。

如果您希望自己的代理人是私有的,或者需要控制代理人的成员名,则需要为包含类型赋予显式数据协定:

[DataContract]
public class SerializeMe
{
    [IgnoreDataMember]
    public DoNotSerializeMe CannotBeSerializedDirectly;

    [DataMember]
    DoNotSerializeMeSurrogate DoNotSerializeMeSurrogate
    {
        get
        {
            if (CannotBeSerializedDirectly == null)
                return null;
            return new DoNotSerializeMeSurrogate { WhyAmIHereSurrogate = CannotBeSerializedDirectly.WhyAmIHere };
        }
        set
        {
            if (value == null)
                CannotBeSerializedDirectly = null;
            else
                CannotBeSerializedDirectly = new DoNotSerializeMe(value.WhyAmIHereSurrogate);
        }
    }

    [DataMember]
    public string SomeOtherField { get; set; }
}

[DataContract]
class DoNotSerializeMeSurrogate
{
    [DataMember]
    public string WhyAmIHereSurrogate { get; set; }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM