Вопрос

I am adapting an existing .NET class library to a Portable Class Library. I am using profile 78 (.NET 4.5, Windows Store 8, Windows Phone 8) in favor of profile 158 (which also targets Silverlight 5) because I want to be able to compile the unsafe code of the original library.

The .NET library contains quite a lot of classes marked [Serializable], so I have implemented a support PCL library containing a dummy SerializableAttribute implementation:

public class SerializableAttribute : Attribute { }

which is referenced from the main PCL library.

To sufficiently use the main PCL library in a .NET application while avoiding type name clashes I have also prepared a .NET support library (with the same strong name as the PCL support library), containing a type forwarding declaration:

[assembly: TypeForwardedTo(SerializableAttribute)]

and in my .NET application explicitly reference the .NET support library instead of the PCL one.

After having prepared all this and being able to successfully compile the PCL adapted library, I am re-using the unit tests from the original .NET library, now referencing the PCL main library and the .NET support library.

This generally works very well, but for unit tests that include a [Serializable] class with an [OnDeserialized] decorated method:

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

I get the following TypeLoadException:

Type 'Foo' in assembly 'MyPclAssembly' has method 'DoSomething' with an incorrect signature for the serialization attribute that it is decorated with.

(It can be noted that OnDeserializedAttribute is included in the portable subset, presumably because it is also recognized in [DataContract] serialization.)

I do not obtain the exception when running the unit tests on the original .NET library. I have carefully analyzed the method signature in the Foo class, and it is completely in line with the signature these (de-) serialization helper methods should have, see e.g. here. I have also tried changing the visibility of the [OnDeserialized] method to internal and public, to no avail.

What is the cause of this exception when using the PCL library, and what can I do to avoid it?


EDIT I have examined the IL code of the PCL library and the .NET library for the [OnDeserialized] method, and I can't see any relevant difference:

PCL

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

.NET

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

The assembly references for StreamingContext are different, but I assume that the PCL System.Runtime.Serialization.Primitives assembly is simply a type forwarding assembly to mscorlib types?

For now, I have decided to exclude the [OnDeserialized] methods from my PCL project, since I do not plan to make use of serialization anyway. An answer to why I am experiencing the TypeLoadException is still welcome, though.

Это было полезно?

Решение

Yeah, this is a game you cannot win. Up front, the [Serializable] attribute is only ever relevant to the BinaryFormatter class, the one that implements binary serialization. That class is not available in the .NET Framework version that's resident on a Phone or a slate so there's no point in trying to make it work.

You are battling the notion of type identity in .NET. Which states that a type is not just identified by the namespace and type name but also the assembly from which it came. It is a very strong anti-DLL Hell countermeasure, the kind you are skirting with here by using types that won't be available on the target architecture.

And the cold hard fact is that in a 4.5 PCL library, the StreamingContext type lives in the System.Runtime.Serialization.dll assembly. An app that targets the desktop will use the one from mscorlib.dll. It is not a forwarded type, it is duplicated. The System.Runtime.Serialization.dll assembly is a small shim assembly with the express intent to isolate these dependencies and prevent DLL Hell.

Kaboom at runtime, it sees a method that has an argument with the wrong type identity.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top