DataContractJsonSerializer;使用.NET调用ISerializable GetObjectData但不使用单

时间:2016-06-21 22:54:40

标签: c# json serialization mono datacontractjsonserializer

以下是我正在努力完成的一个简化示例。

我有一个类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构造函数中。     我创建了它:(用初始构造)

I serialized it: ( constructed with initial )

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

I deserialized it: ( constructed with initial )

显然,如果DoNotSerializeMe真的不可序列化,这会导致错误。

有没有一种优雅的方法可以在不使用Json.NET的情况下解决这个问题?我不确定为什么mono的行为与.NET的行为不同。

1 个答案:

答案 0 :(得分:0)

我将建议一种替代方法:使用代理数据传输类型来序列化您的[MonoTODO]类。一种方法是使用Data Contract Surrogates。但单声道是否支持数据合同代理? current version of the source code表明它们是,但this version将其显示为SerializeMe,因此我无法保证您的单声道版本具有DataContractJsonSerializer.DataContractSurrogate的有效实施。

但是,手动代理属性始终有效。例如,即使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更简单,因为CannotBeSerializedDirectly以外的所有成员都会继续自动序列化。请注意[IgnoreDataMember]的使用。它阻止[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; } } 成员包含在类的隐式数据协定中。

如果您希望您的代理是私有的,或者需要控制代理成员名称,您需要为包含类型提供明确的数据合同:

<div class="b <%= id %>"></div>