我有一个包含来自第三方dll的类的二进制序列化实例的文件集合。我没有访问第三方源代码但我有dll。我需要将这些文件反序列化为类的实例。
我只是这样做:
Stream stream = File.Open(@"C:\my\path", FileMode.Open);
BinaryFormatter binaryFormatter = new BinaryFormatter();
ThirdPartyType o = binaryFormatter.Deserialize(stream) as ThirdPartyType;
stream.Close();
这没有错误。当我在调试模式下运行项目并在反序列化后放置一个断点时,我可以检查实例o
。 o
的所有成员都是null
或0
,因此实例已创建,但没有成员初始化为正确的值。
我尝试反编译dll(使用.Net Reflector)并在以下位置插入断点:
protected ThirdPartyType(SerializationInfo info, StreamingContext context) {}
现在我可以检查参数info
,在这里我可以看到成员m_types
,m_members
& m_data
设置为我期望从序列化文件中获取的正确值。但是,由于某种原因,构造函数不会使用它并正确初始化实例。我只能看到这个构造函数头,反编译器不会显示它的代码。
为了控制初始化,我创建了一个类的本地子类:
[Serializable]
public class FakeThirdPartyType : ThirdPartyType
{
protected FakeThirdPartyType(SerializationInfo info, StreamingContext context) : base(info, context)
{
int width = info.GetInt32("clientWidth");
this.ClientWidth = width;
//Many other properties as well...
}
}
然后我将BinaryFormatter
绑定到SerializationBinder
,当{1}}被要求时,FakeThirdPartyType
会返回ThirdPartyType
(以及其他任何调用的正确类型)。现在,当我运行它时,我会进入我的反序列化构造函数。但在这里我有一个非常奇怪的问题。我可以看到width
被分配了正确的值(!=0
),但在下一行this.ClientWidth
仍然是0
之后。结果与:
base.GetType().GetProperty("ClientWidth").SetValue(this, width, null);
可能有什么我做错了吗?我遇到的问题可能是由交叉装配反序列化引起的吗?错误可能在于我无法访问的第三方代码吗?似乎属性的setter不起作用(至少不会影响getter返回的相同变量)。
在调试过程中,我可以检查ThirdPartyType
类型并看到它有私有字段_clientWidth
,但我找不到任何直接设置的方法。
答案 0 :(得分:0)
在一些反编译后,类的属性都如下所示:
public int Property
{
[MethodImpl(MethodImplOptions.NoInlining)]
get
{
return 0;
}
[MethodImpl(MethodImplOptions.NoInlining)]
set
{
}
}
public Object Property2
{
[MethodImpl(MethodImplOptions.NoInlining)]
get
{
return null;
}
}
这当然是导致反序列化后所有值为null和0的原因。为什么这些属性是这样的,这是一个谜。但这不属于这个问题的范围。