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