我有问题通过DataContract序列化和反序列化单例。
首先是一些事实:
1.) Singleton is "internal"
2.) Singleton contains Dictionaries
我的序列化和反序列化工作正常,但它不是单身人士的正确方法。如果我反序列化xml,我总是生成我的单例的新实例并覆盖单例对象的当前引用 - 但在此之后它不再是单例。
有人有什么想法吗? - 谢谢。
答案 0 :(得分:0)
从msdn检查此link,有一个关于序列化单例的示例。反序列化后,您应该返回引用而不是对象。
答案 1 :(得分:0)
尝试使用NetDataContractSerializer -
NetDataContractSerializer与DataContractSerializer不同 在一个重要的方面:NetDataContractSerializer包括CLR类型 序列化XML中的信息,而DataContractSerializer 才不是。因此,只有在使用NetDataContractSerializer时才能使用 序列化和反序列化两者共享相同的CLR类型。
序列化程序可以将类型序列化为 已经有DataContractAttribute或SerializableAttribute属性 应用。它还序列化了实现ISerializable的类型。
代码示例:
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
class Person : IExtensibleDataObject
{
[DataMember()]
public string FirstName;
[DataMember]
public string LastName;
[DataMember()]
public int ID;
public Person(string newfName, string newLName, int newID)
{
FirstName = newfName;
LastName = newLName;
ID = newID;
}
private ExtensionDataObject extensionData_Value;
public ExtensionDataObject ExtensionData
{
get { return extensionData_Value; }
set { extensionData_Value = value; }
}
}
Searialization:
Person p1 = new Person("Zighetti", "Barbara", 101);
FileStream fs = new FileStream(fileName, FileMode.Create);
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs);
NetDataContractSerializer ser = new NetDataContractSerializer();
ser.WriteObject(writer, p1);
答案 2 :(得分:0)
(.net 4.0的代码)
我有同样的问题: 反序列化需要创建单例类的新实例,它可以(!)执行,因为它在成员函数中:构造函数对成员可见,但该实例不能替换从外部可见的单例实例( “这”)。
因此,您必须将反序列化实例中的属性复制到“this”实例中。
手动复制变得很快,所以这是我的解决方案,使用反射复制未标记的公共可写成员[xmlignore]:
public static class SerializationHelpers
{
/// <summary>
/// Copy all public props and fields that are not xmlignore
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="target"></param>
/// <param name="other"></param>
public static void CopyTypeFields<T>(T target, T other)
{
// get all public static properties of MyClass type
PropertyInfo[] propertyInfos = other.GetType().GetProperties(BindingFlags.Public
| BindingFlags.Instance);
FieldInfo[] fis = other.GetType().GetFields(BindingFlags.Public |
BindingFlags.Instance);
foreach (FieldInfo fi in fis)
{
if ((fi.Attributes & FieldAttributes.FieldAccessMask) !=
FieldAttributes.Literal &&
(fi.Attributes & FieldAttributes.FieldAccessMask) !=
FieldAttributes.Static)
{
if (IsXmlIgnored(fi)) { continue; }
var myval = fi.GetValue(other);
fi.SetValue(target, myval);
}
}
foreach (PropertyInfo pi in propertyInfos)
{
if (!pi.CanWrite || !pi.CanRead) { continue; }
if (IsXmlIgnored(pi)) { continue; }
var myval = pi.GetValue(other, null);
pi.SetValue(target, myval, null);
}
}
private static bool IsXmlIgnored(MemberInfo pi)
{
object[] fiGetCustomAttributes = pi.GetCustomAttributes(false);
foreach (object ob in fiGetCustomAttributes)
{
if (ob.GetType().
Equals(typeof(System.Xml.Serialization.XmlIgnoreAttribute)))
{
return true;
}
}
return false;
}
}
// to use it ...
// the deserialization method of the singleton mySingleton
public bool loadSingleton()
{
bool ret= false;
try
{
Type myType = GetType();
XmlSerializer reader = new XmlSerializer(myType);
try
{
using (StreamReader file = new StreamReader(filename))
{
try
{
mySingleton t1 = (mySingleton)reader.Deserialize(file);
CopySerializationFields(t1);
ret= true;
}
catch
{
...
}
}
}
catch
{
...
}
}
catch (Exception ex)
{
...
}
return ret;
}
private void CopySerializationFields(ProcessingSettings other)
{
SerializationHelpers.CopyTypeFields(this, other);
}
答案 3 :(得分:0)
我刚刚搜索了一个类似的原子类解决方案并找到了answer to a similar problem Marc Gravell。这也适用于单身人士。
在您的单例类中,您实现了由System.Runtime.Serialization.IObjectReference接口定义的GetRealObject方法。如果需要,您还可以将以前序列化的数据添加到单例中,并将静态引用作为反序列化后使用的引用返回。
这是我的例子:
[System.Runtime.Serialization.DataContract]
public class MySingletonClass : System.Runtime.Serialization.IObjectReference
{
private MySingletonClass()
{
}
private static MySingletonClass _Instance;
public static MySingletonClass Instance
{
get
{
if (_Instance == null)
_Instance = new MySingletonClass();
return _Instance;
}
}
object System.Runtime.Serialization.IObjectReference.GetRealObject(System.Runtime.Serialization.StreamingContext context)
{
MySingletonClass realObject = Instance;
realObject.Merge(this);
return realObject;
}
private void Merge(MySingletonClass otherInstance)
{
// do your merging here
}
}
您也可以将它用于原子类。您只需将Instance属性更改为GetInstance方法,并使用GetRealObject方法中的相应属性(即ID)调用它。
答案 4 :(得分:0)
[DataContract]
public sealed class SerializableSingletonPattern
{
public static SerializableSingletonPattern Instance { get; private set; } = new SerializableSingletonPattern();
[DataMember] public bool YourData { get; private set; }
// explicit static constructor so C# compiler will not mark type as beforefieldinit
static SerializableSingletonPattern() { }
SerializableSingletonPattern() // your constructor
{
}
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
Instance = this;
}
}