DataContractJsonSerializer - 共享整个图形的对象实例?

时间:2016-11-21 20:24:44

标签: c# serialization

我使用DataContractJsonSerializer来序列化对象图。当我构造对象时,每个对象都接收对实用程序对象实例的引用(它是一个工厂,用于创建抽象契约类的子类的实例) - 这在图形被序列化然后再次反序列化之前工作得很好,于是对象不再有对实用程序对象的引用。我需要这个参考。您如何推荐我实现此功能(单例不起作用,因为单独的图形需要它们自己的对象实例)?

2 个答案:

答案 0 :(得分:0)

实现此目标的一种方法是使用data contract surrogate。使用代理,您可以在序列化期间用虚拟存根替换“真正的”工厂。然后,在反序列化期间,将假人替换为所需的工厂。

因此,如果您的类看起来像:

public abstract class FactoryBase
{
}

public class Factory : FactoryBase
{
}

public interface IHasFactory
{
    FactoryBase Factory { get; }
}

[DataContract]
public abstract class HasFactoryBase : IHasFactory
{
    [DataMember(IsRequired = true)]
    FactoryBase factory;

    public FactoryBase Factory { get { return factory; } }

    public HasFactoryBase(FactoryBase factory)
    {
        this.factory = factory;
    }
}

[DataContract]
public class Foo : HasFactoryBase
{
    public Foo(FactoryBase factory)
        : base(factory)
    {
        this.Bars = new List<Bar>();
    }

    [DataMember]
    public List<Bar> Bars { get; set; }
}

[DataContract]
public class Bar : HasFactoryBase
{
    public Bar(FactoryBase factory) : base(factory) { }
}

您定义IDataContractSurrogate以使用代理项替换所有出现的FactoryBase,如下所示:

public class FactorySurrogateSelector : IDataContractSurrogate
{
    [DataContract]
    class FactorySurrogate
    {
    }

    readonly FactoryBase factory;

    public FactorySurrogateSelector(FactoryBase factory)
    {
        this.factory = factory;
    }

    #region IDataContractSurrogate Members

    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        throw new NotImplementedException();
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        throw new NotImplementedException();
    }

    public Type GetDataContractType(Type type)
    {
        if (typeof(FactoryBase).IsAssignableFrom(type))
            return typeof(FactorySurrogate);
        return type;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        if (obj is FactorySurrogate)
            return factory;
        return obj;
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
        throw new NotImplementedException();
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (obj is FactoryBase)
        {
            return new FactorySurrogate();
        }
        return obj;
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        throw new NotImplementedException();
    }

    public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
    {
        throw new NotImplementedException();
    }

    #endregion
}

然后,按如下方式序列化和反序列化:

var factory = new Factory();
var test = new Foo(factory)
{
    Bars = { new Bar(factory) },
};

var surrogate = new FactorySurrogateSelector(factory);
var serializer = new DataContractJsonSerializer(test.GetType(), Enumerable.Empty<Type>(), int.MaxValue, false, surrogate, false);

byte[] json;
using (var stream = new MemoryStream())
{
    serializer.WriteObject(stream, test);
    json = stream.ToArray();
}

Foo test2;
using (var stream = new MemoryStream(json))
{
    test2 = (Foo)serializer.ReadObject(stream);
}

if (test2.Factory != test.Factory)
    throw new InvalidOperationException();

请注意,所需的工厂直接传递到FactorySurrogateSelector的构造函数中,然后最终设置在包含工厂类型实例的每个类型中。

生成的JSON将如下所示:

{
  "factory": {},
  "Bars": [
    {
      "factory": {}
    }
  ]
}

一些资格:

  • 您的工厂必须继承一些公共基类,此处为FactoryBase。数据协定序列化程序将从不序列化接口成员,例如IFactory factory其中IFactory是您的工厂界面,即使有适用的代理商也是如此。

  • 空的"factory": {}对象必须出现在JSON中,以便代理在反序列化期间注入正确的“实际”工厂值。因此[DataMember(IsRequired = true)]

答案 1 :(得分:0)

另一种方法是引入thread staticthread local工厂对象,然后使用[OnDeserializing] callback使用它填充您的类。

因此,如果您按如下方式定义类型:

public interface IFactory
{
}

public class Factory : IFactory
{
}

public interface IHasFactory
{
    IFactory Factory { get; }
}

[DataContract]
public abstract class HasFactoryBase : IHasFactory
{
    [ThreadStatic]
    static IFactory deserializedFactory;

    static IFactory DeserializedFactory
    {
        get
        {
            return deserializedFactory;
        }
        set
        {
            deserializedFactory = value;
        }
    }

    public static IDisposable SetDeserializedFactory(IFactory factory)
    {
        return new PushValue<IFactory>(factory, () => DeserializedFactory, val => DeserializedFactory = val);
    }

    IFactory factory;

    public IFactory Factory { get { return factory; } }

    public HasFactoryBase(IFactory factory)
    {
        this.factory = factory;
    }

    [OnDeserializing]
    void OnDeserializing(StreamingContext context)
    {
        this.factory = DeserializedFactory;
    }
}

public struct PushValue<T> : IDisposable
{
    Action<T> setValue;
    T oldValue;

    public PushValue(T value, Func<T> getValue, Action<T> setValue)
    {
        if (getValue == null || setValue == null)
            throw new ArgumentNullException();
        this.setValue = setValue;
        this.oldValue = getValue();
        setValue(value);
    }

    #region IDisposable Members

    // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
    public void Dispose()
    {
        if (setValue != null)
            setValue(oldValue);
    }

    #endregion
}

[DataContract]
public class Foo : HasFactoryBase
{
    public Foo(IFactory factory)
        : base(factory)
    {
        this.Bars = new List<Bar>();
    }

    [DataMember]
    public List<Bar> Bars { get; set; }
}

[DataContract]
public class Bar : HasFactoryBase
{
    public Bar(IFactory factory) : base(factory) { }
}

您可以按如下方式序列化和反序列化:

var factory = new Factory();
var test = new Foo(factory)
{
    Bars = { new Bar(factory) },
};

var serializer = new DataContractJsonSerializer(test.GetType());

byte [] json;
using (var stream = new MemoryStream())
{
    serializer.WriteObject(stream, test);
    json = stream.ToArray();
}

Foo test2;
using (HasFactoryBase.SetDeserializedFactory(factory))
using (var stream = new MemoryStream(json))
{
    test2 = (Foo)serializer.ReadObject(stream);
}

if (test2.Factory != test.Factory)
    throw new InvalidOperationException();

JSON看起来像:

{
  "Bars": [
    {}
  ]
}

一些注意事项:

  • 工厂对象在JSON中根本没有出现。

  • 工厂对象不再需要从某个抽象基类继承,它们可以简单地实现一个通用的IFactory接口。