C# 通过DataContract序列化单例
我在通过DataContract序列化和反序列化单例时遇到问题 首先是一些事实:C# 通过DataContract序列化单例,c#,singleton,datacontract,internal,serialization,C#,Singleton,Datacontract,Internal,Serialization,我在通过DataContract序列化和反序列化单例时遇到问题 首先是一些事实: 1.) Singleton is "internal" 2.) Singleton contains Dictionaries 我的序列化和反序列化工作得很好,但对于单例来说这不是正确的方式。如果我反序列化xml,我总是生成我的singleton的一个新实例,并覆盖singleton对象的当前引用——但在此之后,它就不再是singleton了 有人知道吗谢谢。请查看msdn,这里有一个序列化单例的示例。反序列化后
1.) Singleton is "internal"
2.) Singleton contains Dictionaries
我的序列化和反序列化工作得很好,但对于单例来说这不是正确的方式。如果我反序列化xml,我总是生成我的singleton的一个新实例,并覆盖singleton对象的当前引用——但在此之后,它就不再是singleton了
有人知道吗谢谢。请查看msdn,这里有一个序列化单例的示例。反序列化后,应返回引用而不是对象。尝试使用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);
(用于.net 4.0的代码)
我也有同样的问题:
反序列化需要创建singleton类的新实例,它可以(!)这样做,因为它位于成员函数内部:构造函数对成员可见,但该实例不能替换从外部可见的singleton实例(“this”)
因此,必须将反序列化实例中的属性复制到“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);
}
公共静态类序列化助手
{
///
///复制所有不可忽略的公共道具和字段
///
///
///
///
公共静态void CopyTypeFields(T目标,T其他)
{
//获取MyClass类型的所有公共静态属性
PropertyInfo[]propertyInfos=other.GetType().GetProperties(BindingFlags.Public
|BindingFlags.Instance);
FieldInfo[]fis=other.GetType().GetFields(BindingFlags.Public)
BindingFlags.Instance);
foreach(fis中的FieldInfo fi)
{
if((fi.Attributes和FieldAttributes.FieldAccessMask)!=
FieldAttributes.Literal&&
(fi.Attributes和FieldAttributes.FieldAccessMask)!=
字段属性(静态)
{
如果(IsXmlIgnored(fi)){continue;}
var myval=fi.GetValue(其他);
fi.设定值(目标,myval);
}
}
foreach(PropertyInfo中的PropertyInfo pi)
{
如果(!pi.CanWrite | |!pi.CanRead){continue;}
如果(IsXmlIgnored(pi)){continue;}
var myval=pi.GetValue(其他,空);
pi.SetValue(target,myval,null);
}
}
私有静态bool IsXmlIgnored(MemberInfo pi)
{
对象[]fiGetCustomAttributes=pi.GetCustomAttributes(false);
foreach(fiGetCustomAttributes中的对象对象对象)
{
if(ob.GetType()。
等于(typeof(System.Xml.Serialization.XmlIgnoreAttribute)))
{
返回true;
}
}
返回false;
}
}
//要使用它。。。
//单例mySingleton的反序列化方法
公共bool loadSingleton()
{
bool-ret=假;
尝试
{
类型myType=GetType();
XmlSerializer reader=新的XmlSerializer(myType);
尝试
{
使用(StreamReader文件=新StreamReader(文件名))
{
尝试
{
mySingleton t1=(mySingleton)reader;
CopySerializationFields(t1);
ret=真;
}
接住
{
...
}
}
}
接住
{
...
}
}
捕获(例外情况除外)
{
...
}
返回ret;
}
私有void CopySerializationFields(处理设置其他)
{
SerializationHelpers.CopyTypeFields(这个,其他);
}
我刚刚搜索了很长时间,寻找类似的原子类解决方案,并找到了一个by。这也适用于单身人士
在singleton类中,实现由接口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)调用它即可。如果要覆盖实例,它实际上不是单例,是吗?:)那么为什么要为单身模式烦恼呢?是的,你是对的。但我认为这是一个肮脏的,不是通常的方式,使“一个单身一个单身”。还是这样?:)这不是正确的方法-在使用数据协定属性之前,我不能使用ISerializer。我遇到以下异常:“ConfigurationData”类型不能是ISerializable,并且具有DataContractAttribute属性。
[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;
}
}