2016-11-21 56 views
0

我正在使用DataContractJsonSerializer來序列化對象圖。當我構造這些對象時,每個對象都會接收到一個實用對象實例的引用(它是一個工廠,用於創建抽象合約類的子類的實例) - 這非常有效,直到圖形被序列化,然後再次反序列化爲止,不再有對實用對象的引用。我需要這個參考。你會如何建議我實現這個(單身不工作,因爲單獨的圖需要他們自己的對象實例)?DataContractJsonSerializer - 爲整個圖形共享一個對象實例?

回答

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(); 

注意: t期望的工廠直接進入FactorySurrogateSelector的構造函數,然後最終設置在每個包含工廠類型實例的類型中。

產生的JSON的樣子:

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

一些資歷:

  • 你的工廠必須從一些公共基類繼承,這裏FactoryBase。數據合同序列化器將從永不序列化接口成員,例如, IFactory factory其中IFactory是您的工廠界面,即使有適用的代理商也是如此。

  • 空的"factory": {}對象必須出現在JSON中,以便代理在反序列化期間注入正確的「真實」工廠值。因此[DataMember(IsRequired = true)]

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

相關問題