13

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.

2
  • I'm trying to use PCL-version of your AForge and Accord Neuro, but when I try to save a network after having trained it, I get 'System.PlatformNotSupportedException' for BinaryFormatter. Did you figure out a solution this? Commented May 21, 2015 at 20:16
  • Please excuse my sloppiness - reading the actual Accord documentation and adding the Shim nuget package solved the problem in my previous comment. Commented May 21, 2015 at 21:08

1 Answer 1

6
+250

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, @Hans. Can you provide a reference or an example link to confirm the statement "a type is not just identified by the namespace and type name but also the assembly from which it came"?
We create linkable posts around here. Use google for links. A query like ".NET type identity" ought to help. The second hit is about type equivalence, very relevant.
Hey, keep your pants on. It was not a guess, I would have explicitly stated so of course. Your lack of research does not create an obligation on my part.
For the record, I have spent considerable time PCL:ing and open sourcing a large image processing library, and to the largest extent possible I would like to keep all .NET Framework functionality available when invoking the PCL library from a .NET application. If there is any way to workaround the above [OnDeserialized] issue it would be awesome to learn about it. If there is not, an official confirmation that it cannot work would convince me more definitely that I should stop banging my head over the issue.
This also affects .NET Standard / .NET Core too github.com/dotnet/standard/issues/300

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.