2012-10-31 32 views
20

我正在使用BinaryFormatter在C#中对二进制序列化一些对象。但是,某些对象包含通过DLL访问并且没有源代码的类,因此我无法使用Serializable属性标记它们。无论如何,有没有简单的方法来序列化它们?我有一个解决方法,涉及采取类NoSource并创建一个新的类SerializableNoSource其构造函数采取NoSource对象,并从中提取所需的所有信息,但它是hacky。有没有更好的选择?当你没有类的源代码时,是否可以对对象进行.NET二进制序列化?

+7

为了记录,将对象封装到另一个* * *知道如何序列化自己以及从封装对象转换到/从封装对象转换的对象在我的脑海中并不是一件好事,这完全合适。现在,可能会出现一些变化,但我不认为你目前的方法存在根本上的缺陷。 – Servy

回答

-2

我认为更干净的方法是实现ISerializable接口并管理序列化和逆向过程。 在MSDN我们可以发现:

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

+0

“但是,某些对象包含通过DLL访问的类,并且没有” –

+0

“的源代码您可以认为创建自己的类可以具有与没有源的对象相同的属性不是?或者扩展它? –

+0

扩展将无法工作,复制属性...这与他现在具有的相同 –

1

您可能能够使用Mono.Cecil[SerializableAttribute]添加到类,但如果有另一种达到预期结果的方式,我不会这样做。

0

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

0

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

如果这个类是封装的,那么你可以使用Json.NET,然后将其转换为二进制,反之亦然(如果没有别的东西可以帮助,就使用它)。

20

您可以创建一个序列化替代品

假设我们有一个引用的程序集,我们已经在没有控制的定义,一类是这样的:

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

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

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

+0

这似乎是教科书的答案,以真正序列化未标记为[[Serializable]的无主类] –

+0

如果您需要更多信息你可以阅读[CLR via C#]的第23章(http://www.amazon.co.uk/CLR-via-C-Jeffrey-Richter/dp/0735627045) - 运行时序列化。 –

+0

还在MSDN上发现了这篇相关文章:http://msdn.microsoft.com/en-us/magazine/cc188950.aspx –

相关问题