- PVSM.RU - https://www.pvsm.ru -
Штатная десериализация .net всегда создает граф новых объектов. Это не всегда удобно.
Поиск не дал готового ответа. Есть не самые простые решения с использованием protobuf и прочих сторонних сериализаторов, но это не всегда применимо.
Задача в целом несложная, и мое решение не является чем то выдающимся, но с другой стороны, тем кто впервые столкнется с похожей проблемой — будет проще.
Сериализация делается как обычно. Следующие 2 класса решат проблему при десериализации.
[Serializable]
public class RealObjectHelper : IObjectReference, ISerializable
{
Object m_realObject;
virtual object getObject(ObjectId id)
{
//Этот метод должен возвращать ваш объект,
return id.GetObject();
}
public RealObjectHelper(SerializationInfo info, StreamingContext context)
{
ObjectId id = (ObjectId)info.GetValue("ID", typeof(ObjectId));
m_realObject = getObject(id);
if(m_realObject == null)
return;
Type t = m_realObject.GetType();
MemberInfo[] members = FormatterServices.GetSerializableMembers(t, context);
List<MemberInfo> deserializeMembers = new List<MemberInfo>(members.Length);
List<object> data = new List<object>(members.Length);
foreach(MemberInfo mi in members)
{
Type dataType = null;
if(mi.MemberType == MemberTypes.Field)
{
FieldInfo fi = mi as FieldInfo;
dataType = fi.FieldType;
} else if(mi.MemberType == MemberTypes.Property){
PropertyInfo pi = mi as PropertyInfo;
dataType = pi.PropertyType;
}
try
{
if(dataType != null){
data.Add(info.GetValue(mi.Name, dataType));
deserializeMembers.Add(mi);
}
}
catch (SerializationException)
{
//some fiels are missing, new version, skip this fields
}
}
FormatterServices.PopulateObjectMembers(m_realObject, deserializeMembers.ToArray(), data.ToArray());
}
public object GetRealObject( StreamingContext context )
{
return m_realObject;
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
}
}
public class RealObjectBinder: SerializationBinder
{
String assemVer;
String typeVer;
public RealObjectBinder(String asmName, String typeName)
{
assemVer = asmName;
typeVer = typeName;
}
public override Type BindToType( String assemblyName, String typeName )
{
Type typeToDeserialize = null;
if ( assemblyName.Equals( assemVer ) && typeName.Equals( typeVer ) )
{
return typeof(RealObjectHelper);
}
typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) );
return typeToDeserialize;
}
}
При десериализации надо установить Binder, который создаст обертку для десериализации в ваш существующий объект.
BinaryFormatter bf = new BinaryFormatter(null, context);
bf.Binder = new RealObjectBinder(YourType.Assembly.FullName, YourType.FullName);
bf.Deserialize(memStream);
Автор: mdaemon
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/20834
Ссылки в тексте:
[1] Источник: http://habrahabr.ru/post/159855/
Нажмите здесь для печати.