我正在使用BinaryFormatter
在C#中对二进制序列化一些对象。但是,某些对象包含通过DLL访问并且没有源代码的类,因此我无法使用Serializable
属性标记它们。无论如何,有没有简单的方法来序列化它们?我有一个解决方法,涉及采取类NoSource
并创建一个新的类SerializableNoSource
其构造函数采取NoSource
对象,并从中提取所需的所有信息,但它是hacky。有没有更好的选择?当你没有类的源代码时,是否可以对对象进行.NET二进制序列化?
回答
我认为更干净的方法是实现ISerializable接口并管理序列化和逆向过程。 在MSDN我们可以发现:
系列化不能被添加到一个类就已经 编译后....
“但是,某些对象包含通过DLL访问的类,并且没有” –
“的源代码您可以认为创建自己的类可以具有与没有源的对象相同的属性不是?或者扩展它? –
扩展将无法工作,复制属性...这与他现在具有的相同 –
您可能能够使用Mono.Cecil到[SerializableAttribute]
添加到类,但如果有另一种达到预期结果的方式,我不会这样做。
我同意@Servy,如果类的作者没有预料到它会被序列化,你不应该试图直接序列化它。所以你从架构的角度来看是正确的。为了减少当前的方法,“hacky”,考虑对包含对不可序列化对象的引用的类实施ISerializable。
创建一个新类,继承未标记序列化属性的现有类并实现ISerializable接口。
如果这个类是封装的,那么你可以使用Json.NET,然后将其转换为二进制,反之亦然(如果没有别的东西可以帮助,就使用它)。
您可以创建一个序列化替代品。
假设我们有一个引用的程序集,我们已经在没有控制的定义,一类是这样的:
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);
}
}
使用序列化代理绝不是简单的,并且实际上可以变得相当冗长,当你试图序列类型有需要序列私人&保护领域。
但是,由于您已经手动序列化所需的值,因此我认为这不是问题。代理人的使用是处理这种情况的更统一的方式,应该让你感觉更舒适。
这似乎是教科书的答案,以真正序列化未标记为[[Serializable]的无主类] –
如果您需要更多信息你可以阅读[CLR via C#]的第23章(http://www.amazon.co.uk/CLR-via-C-Jeffrey-Richter/dp/0735627045) - 运行时序列化。 –
还在MSDN上发现了这篇相关文章:http://msdn.microsoft.com/en-us/magazine/cc188950.aspx –
- 1. C#对象二进制序列化
- 2. 在二进制序列化(二进制)期间是否有机会保存对象的哈希码?
- 3. .net中的二进制序列化/反序列化对象图大小是否有任何限制?
- 4. .NET:如何用属性[DataContract]二进制序列化对象?
- 5. 如何在可移植类库中对二进制类进行序列化?
- 6. 是否存在可二进制序列化的XML特定对象(如XElement)?
- 7. 源代码,二进制,列表,续行
- 8. 对二进制类文件的内容进行反序列化时的ClassNotFoundException
- 9. 是否可以通过Resharper对代码进行排序?
- 10. gcc是否有可能对生成的二进制进行不同的排序?
- 11. 可以使用Java对Method对象进行序列化?
- 12. 序列化时,二进制格式化程序是否对空间很敏感?
- 13. 你可以对代码片段表进行排序吗?
- 14. 你可以在运行时使对象可序列化吗?
- 15. 是否有可能对Javers Diff进行反序列化?
- 16. 反序列化二进制对象时获取版本
- 17. 如何对二进制文件进行反序列化
- 18. TensorFlow:如何使用RNN对二进制序列进行分类?
- 19. 是否可以对特定的错误代码进行pylint?
- 20. 不断变化的类的源代码序列化对象
- 21. .net二进制序列化 - 选项
- 22. .NET中是否有可序列化的通用键/值对类?
- 23. 是否可以将java类对象序列化为类文件?
- 24. 在二进制序列化(C#)中如何跳过可序列化对象中的不可序列化字段?
- 25. 排除父对象上的二进制序列化在C#
- 26. Java - 修改二进制序列化对象的serialVersionUID
- 27. Silverlight的对象二进制序列化到数据库
- 28. 反序列化二进制文件中的对象
- 29. 二进制反序列化的通用对象
- 30. 是否有可能阅读并进入.NET Framework源代码
为了记录,将对象封装到另一个* * *知道如何序列化自己以及从封装对象转换到/从封装对象转换的对象在我的脑海中并不是一件好事,这完全合适。现在,可能会出现一些变化,但我不认为你目前的方法存在根本上的缺陷。 – Servy