在.NET应用程序中使用PCL时,如果被调用的类包含[OnDeserialized]方法,则为TypeLoadException

时间:2013-12-18 19:27:03

标签: c# serialization attributes forward-declaration portable-class-library

我正在将现有的.NET类库改编为可移植类库。我使用配置文件78(.NET 4.5,Windows Store 8,Windows Phone 8)支持配置文件158(也针对Silverlight 5),因为我希望能够编译原始库的unsafe代码。

.NET库包含很多标记为[Serializable]的类,因此我实现了一个包含虚拟SerializableAttribute实现的支持PCL库:

public class SerializableAttribute : Attribute { }

从主PCL库中引用。

为了充分利用.NET应用程序中的主PCL库,同时避免类型名称冲突,我还准备了一个.NET支持库(具有与PCL支持库相同的名称),包含类型转发声明:

[assembly: TypeForwardedTo(SerializableAttribute)]

并在我的.NET应用程序中显式引用.NET支持库而不是PCL库。

在准备好所有这些并且能够成功编译PCL适配库之后,我重新使用原始.NET库中的单元测试,现在引用 PCL 主库和< em> .NET 支持库。

这通常效果很好,但适用于包含[Serializable]类和[OnDeserialized]修饰方法的单元测试:

[Serializable]
public class Foo
{
    [OnDeserialized]
    private void DoSomething(StreamingContext context) { }
}

我得到以下TypeLoadException

  

在程序集“MyPclAssembly”中键入“Foo”的方法“DoSomething”,其序列化属性的签名不正确。

(可以注意到OnDeserializedAttribute 包含在便携式子集中,可能是因为它在[DataContract]序列化中也被识别出来。)

在原始.NET库上运行单元测试时,我获取异常。我仔细分析了Foo类中的方法签名,它完全符合这些(de-)序列化辅助方法应该具有的签名,参见例如here。我也尝试将[OnDeserialized]方法的可见性更改为internalpublic,但无济于事。

使用PCL库时出现此异常的原因是什么,我该怎么做才能避免它?


编辑我已经检查过 PCL 库的 IL 代码和 .NET 库{1}}方法,我看不出任何相关的区别:

PCL

[OnDeserialized]

.NET

.method private hidebysig instance void DoSomething(valuetype [System.Runtime.Serialization.Primitives]System.Runtime.Serialization.StreamingContext context) cil managed

.method private hidebysig instance void DoSomething(valuetype [mscorlib]System.Runtime.Serialization.StreamingContext context) cil managed 的程序集引用不同,但我认为PCL System.Runtime.Serialization.Primitives 程序集只是 mscorlib 类型?

目前,我已决定从我的PCL项目中排除StreamingContext方法,因为我无论如何都不打算使用序列化。不过,我仍然欢迎您回答我遇到[OnDeserialized]的原因。

1 个答案:

答案 0 :(得分:6)

是的,这是一场你无法获胜的比赛。在前面,[Serializable]属性只与BinaryFormatter类相关,后者是实现二进制序列化的类。该类在.NET Framework版本中可用于电话或平板上,因此尝试使其无效是没有意义的。

您正在与.NET中的类型标识的概念作斗争。这表明类型不仅仅由命名空间和类型名称标识,而且还标识了它来自的程序集。这是一个非常强大的反DLL地狱对策,你可以通过使用目标架构上不可用的类型来避开这种对抗。

而冷酷的事实是,在4.5 PCL库中,StreamingContext类型存在于System.Runtime.Serialization.dll程序集中。针对桌面的应用程序将使用mscorlib.dll中的应用程序。 不是转发类型,它是重复的。 System.Runtime.Serialization.dll程序集是一个小的填充程序集,明确意图隔离这些依赖项并防止DLL Hell。

Kaboom在运行时,它会看到一个方法,其参数的类型标识错误。