如何反序列化为现有对象 - C#

rob*_*rob 12 c# serialization

在C#中,在将对象序列化到文件之后,如何在不创建新对象的情况下将文件反序列化为现有对象?

我可以找到的自定义序列化的所有示例都涉及实现一个将在反序列化时调用的构造函数,这正是我想要的,除了我不希望函数成为构造函数.

谢谢!

Mar*_*ell 8

一些序列化程序支持回调; 例如,both BinaryFormatterDataContractSerializer(和protobuf-net,下面)允许你指定一个before-serializaton回调,并且由于它们跳过构造函数,这可能足以初始化对象.但是,序列化程序仍在创建它.


大多数序列化程序都想要自己创建新对象,但有些序列化程序允许您反序列化为现有对象.嗯,实际上唯一一个跳跃到脑海的人是protobuf-net(披露:我是作者)......

这有两个不同的功能可能会有所帮助; 对于对象(即图中最外面的对象),您可以将现有对象直接提供给Merge方法(在v1中,在v2中也为了兼容性),或者在(在v2中)Deserialize方法; 例如:

var obj = Serializer.Merge<YourType>(source, instance);
Run Code Online (Sandbox Code Playgroud)

但是,在较大的图形中,您可能希望自己提供其他对象(而不仅仅是根目录).以下内容未在属性 API中公开,但是是v2中的新功能:

RuntimeTypeModel.Default[typeof(SomeType)].SetFactory(factoryMethod);
Run Code Online (Sandbox Code Playgroud)

where factoryMethod可以是(返回实例)中的方法的名称,也可以是任何地方的任何方法.如果需要,该方法还可以(可选)将序列化上下文作为参数.然后应该使用此方法提供所有新实例.staticSomeTypeSomeTypeMethodInfostaticSomeType


注意:protobuf-net与... 完全相同BinaryFormatter; 为了获得最佳效果,您需要告诉它如何映射您的成员 - 非常类似于标记[DataMember]WCF/DataContractSerializer的内容.这可以是属性,但不是必须的.


Ale*_*der 5

没问题,只需使用2个班级.在getObject方法中,您将获得现有对象

[Serializable]
public class McRealObjectHelper : IObjectReference, ISerializable 
{
    Object m_realObject;
    virtual object getObject(McObjectId id)
    {
        return id.GetObject();
    }
    public McRealObjectHelper(SerializationInfo info, StreamingContext context)
    {
        McObjectId id = (McObjectId)info.GetValue("ID", typeof(McObjectId));
        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 McRealObjectBinder: SerializationBinder
{
    String assemVer;
    String typeVer;
    public McRealObjectBinder(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(McRealObjectHelper);
        }
        typeToDeserialize = Type.GetType( String.Format(  "{0}, {1}", typeName, assemblyName ) );
        return typeToDeserialize;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,反序列化时:

BinaryFormatter bf = new BinaryFormatter(null, context);
bf.Binder = new McRealObjectBinder(YourType.Assembly.FullName, YourType.FullName);
bf.Deserialize(memStream);
Run Code Online (Sandbox Code Playgroud)