-->

是否有可能做一个对象的.NET二进制序列化时,你没有这个类的源代码?(Is it possible

2019-06-18 18:27发布

I am using BinaryFormatter to do binary serialization of some objects in C#. However, some of the objects contain classes that I access via a DLL and do not have the source code for, so I can't mark them with the Serializable attribute. Is there a straightforward way to serialize them anyway? I have a workaround which involves taking class NoSource and making a new class SerializableNoSource for which the constructor takes a NoSource object and extracts all the information I need from it, but it's hacky. Are there any better alternatives?

Answer 1:

您可以创建一个序列化代理

试想一下,我们有一个引用的程序集,我们有过不控制是这样定义的类:

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; }
}

为了序列化这个对象,你需要定义序列化代理的对象图中的每一种类型。

要创建您只需创建一个实现一个类型序列化代理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;
    }
}

然后,你需要让你的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);
    }
}

使用序列化代理绝不是简单的,并且实际上可以变得相当冗长,当你试图序列类型有需要序列私人及保护领域。

但是,正如你已经手动序列化您需要的价值观,我不认为这是一个问题。 使用替代的是处理一个场景像这样的更unifom方式应该让你感觉更舒服。



Answer 2:

你也许能够使用Mono.Cecil能在添加[SerializableAttribute]的类,但如果达不到预期结果的另一种方式,我不会去做。



Answer 3:

我同意@Servy,如果类的作者没有预料到它会被序列化,你不应该试图直接序列化。 所以你从架构的角度来看做正确的事。 为了使您目前的做法少,“哈克,”考虑实施了ISerializable对于包含非序列化对象的引用的类。



Answer 4:

创建一个新的类,继承未标有序列化属性,实现ISerializable接口现有的类。

如果类是密封的,那么你可以使用Json.NET,然后将其转换为二进制,反之亦然(吮吸大的时候,使用它,如果没有其他可以帮助:))。



Answer 5:

我认为,更清洁的方式将implenment ISerializable接口和疥癣自己的序列化和逆过程。 在MSDN我们可以发现:

序列化不能被添加到一个类已经编译后....



文章来源: Is it possible to do .NET binary serialization of an object when you don't have the source code of the class?