当您没有类的源代码时,是否可以对对象进行 .NET 二进制序列化? [英] Is it possible to do .NET binary serialization of an object when you don't have the source code of the class?
问题描述
我正在使用 BinaryFormatter
对 C# 中的某些对象进行二进制序列化.但是,某些对象包含我通过 DLL 访问的类并且没有源代码,所以我不能用 Serializable
属性标记它们.有没有一种直接的方法来序列化它们?我有一个解决方法,它涉及获取类 NoSource
并创建一个新类 SerializableNoSource
,其中构造函数获取一个 NoSource
对象并提取我的所有信息需要它,但它很hacky.有没有更好的选择?
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?
推荐答案
您可以创建一个序列化代理.
想象一下,我们在引用程序集中定义了一个我们无法控制的类,如下所示:
Imagine that we have a class defined in a referenced assembly that we have no control over that looks like this:
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; }
}
为了序列化这个对象,你需要为对象图中的每个类型定义一个序列化代理.
In order to serialize this object you will need to define a serialization surrogate for each type in the object graph.
要创建序列化代理,您只需创建一个实现 ISerializationSurrogate
接口:
To create a serialization surrogate you simply need to create a type that implements the ISerializationSurrogate
interface:
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;
}
}
然后,您需要通过定义和初始化 SurrogateSelector
并将其分配给您的 IFormatter
来让您的 IFormatter
了解代理项.>
Then you need to let your IFormatter
know about the surrogates by defining and initializing a SurrogateSelector
and assigning it to your 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);
}
}
使用序列化代理绝不简单,当您尝试序列化的类型具有 private &需要序列化的受保护字段.
Using a serialization surrogate is by no means straightforward, and can actually become quite verbose when the type you are trying to serialize has private & protected fields that need to be serialized.
但是由于您已经手动序列化了您需要的值,我认为这不是问题.使用代理是处理此类场景的更统一的方式,应该会让您感觉更舒服.
But as you are already manually serializing the values you need, I don't think that is an issue. The use of a surrogate is a more unifom way of handling a scenario like this and should make you feel more comfortable.
这篇关于当您没有类的源代码时,是否可以对对象进行 .NET 二进制序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!