当你没有类的源代码时,是否可以对对象进行.NET二进制序列化?

Cra*_*g W 24 .net c# binary serialization binary-serialization

我正在使用BinaryFormatterC#中的某些对象进行二进制序列化.但是,某些对象包含我通过DLL访问但没有源代码的类,因此我无法使用该Serializable属性标记它们.是否有一种简单的方法来序列化它们?我有一个解决方法,涉及获取类NoSource和创建一个新类SerializableNoSource,构造函数接受一个NoSource对象,并从中提取我需要的所有信息,但它是hacky.还有更好的选择吗?

Use*_*678 24

您可以创建序列化代理.

想象一下,我们在引用的程序集中定义了一个类,我们无法控制它,如下所示:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DriversLicense License;
}


// An instance of this type will be part of the object graph and will need to be 
// serialized also.
public class DriversLicense
{
    public string Number { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

为了序列化此对象,您需要为对象图中的每个类型定义序列化代理.

要创建序列化代理,您只需创建一个实现该ISerializationSurrogate接口的类型:

public class PersonSurrogate : ISerializationSurrogate
{
    /// <summary>
    /// Manually add objects to the <see cref="SerializationInfo"/> store.
    /// </summary>
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        Person person = (Person) obj;
        info.AddValue("Name", person.Name);
        info.AddValue("Age", person.Age);
        info.AddValue("License", person.License);
    }

    /// <summary>
    /// Retrieves objects from the <see cref="SerializationInfo"/> store.
    /// </summary>
    /// <returns></returns>
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        Person person = (Person)obj;
        person.Name = info.GetString("Name");
        person.Age = info.GetInt32("Age");
        person.License = (DriversLicense) info.GetValue("License", typeof(DriversLicense));
        return person;
    }
}

public class DriversLicenseSurrogate : ISerializationSurrogate
{
    /// <summary>
    /// Manually add objects to the <see cref="SerializationInfo"/> store.
    /// </summary>
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        DriversLicense license = (DriversLicense)obj;
        info.AddValue("Number", license.Number);
    }

    /// <summary>
    /// Retrieves objects from the <see cref="SerializationInfo"/> store.
    /// </summary>
    /// <returns></returns>
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        DriversLicense license = (DriversLicense)obj;
        license.Number = info.GetString("Number");
        return license;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您需要IFormatter通过定义和初始化SurrogateSelector并将其分配给您的代理来让您了解代理IFormatter.

private static void SerializePerson(Person person)
{
    if (person == null)
        throw new ArgumentNullException("person");

    using (var memoryStream = new MemoryStream())
    {
        //Configure our surrogate selectors.
        var surrogateSelector = new SurrogateSelector();
        surrogateSelector.AddSurrogate(typeof (Person), new StreamingContext(StreamingContextStates.All),
                                       new PersonSurrogate());
        surrogateSelector.AddSurrogate(typeof (DriversLicense), new StreamingContext(StreamingContextStates.All),
                                       new DriversLicenseSurrogate());

        //Serialize the object
        IFormatter formatter = new BinaryFormatter();
        formatter.SurrogateSelector = surrogateSelector;
        formatter.Serialize(memoryStream, person);

        //Return to the beginning of the stream
        memoryStream.Seek(0, SeekOrigin.Begin);

        //Deserialize the object
        Person deserializedPerson = (Person) formatter.Deserialize(memoryStream);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用序列化代理并不简单,当您尝试序列化的类型具有需要序列化的私有和受保护字段时,实际上可能会变得非常冗长.

但是,由于您已经手动序列化了所需的值,我认为这不是问题.使用代理是一种更加统一的处理这种情况的方式,应该让你感觉更舒服.


Ala*_*RNE -2

我认为更干净的方法是实现 ISerialized Interface 并自行管理序列化和逆向过程。在MSDN中我们可以找到:

编译后的类无法添加序列化......