TypeLoadException при использовании PCL в приложении .NET, если вызываемый класс содержит метод [OnDeserialized]

Я адаптирую существующую библиотеку классов .NET к переносимой библиотеке классов. Я использую профиль 78 (.NET 4.5, Windows Store 8, Windows Phone 8) в пользу профиля 158 (который также нацелен на Silverlight 5), потому что я хочу иметь возможность компилировать код unsafe исходной библиотеки.

В библиотеке .NET содержится довольно много классов с пометкой [Serializable], поэтому я внедрил библиотеку поддержки PCL, содержащую реалистичную реализацию SerializableAttribute:

public class SerializableAttribute : Attribute { }

на который ссылается основная библиотека PCL.

Чтобы достаточно использовать основную библиотеку PCL в .NET-приложении, избегая конфликтов имен типов, я также подготовил библиотеку поддержки .NET(с тем же именем, что и библиотека поддержки PCL), содержащую объявление пересылки типов:

[assembly: TypeForwardedTo(SerializableAttribute)]

и в моем приложении .NET явно ссылаются на библиотеку поддержки .NET вместо PCL.

После того, как вы подготовили все это и смогли успешно скомпилировать библиотеку, адаптированную к PCL, я повторно использую модульные тесты из исходной библиотеки .NET, теперь ссылаясь на основную библиотеку PCL и библиотеку поддержки .NET.

Это обычно работает очень хорошо, но для модульных тестов, которые включают класс [Serializable] с [OnDeserialized] оформленным способом:

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

Я получаю следующее TypeLoadException:

Тип 'Foo' в сборке 'MyPclAssembly' имеет метод DoSomething с неправильной сигнатурой для атрибута сериализации, который он украшен.

(Можно отметить, что OnDeserializedAttribute включен в переносное подмножество, предположительно потому, что он также распознается в сериализации [DataContract].)

Я не получаю исключение при выполнении модульных тестов в исходной библиотеке .NET. Я тщательно проанализировал подпись метода в классе Foo и полностью согласуется с сигнатурой, которую должны иметь эти вспомогательные методы сериализации (см. здесь. Я также попытался изменить видимость метода [OnDeserialized] на internal и public, но безрезультатно.

В чем причина этого исключения при использовании библиотеки PCL и что я могу сделать, чтобы избежать этого?


EDIT Я изучил IL-код библиотеки PCL и библиотеки .NET для метода [OnDeserialized], и я не вижу никакой существенной разницы:

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

Ссылки на сборку для StreamingContext различны, но я предполагаю, что сборка PCL System.Runtime.Serialization.Primitives - это просто переадресация типа к типам mscorlib?

В настоящее время я решил исключить методы [OnDeserialized] из моего проекта PCL, так как я вообще не планирую использовать сериализацию. Ответ на то, почему я испытываю TypeLoadException, по-прежнему приветствуется.

Ответ 1

Да, это игра, которую вы не можете выиграть. Наверху, атрибут [Serializable] всегда применим только к классу BinaryFormatter, который реализует двоичную сериализацию. Этот класс недоступен в версии .NET Framework, которая находится на телефоне или слайде, поэтому нет смысла пытаться заставить его работать.

Вы сражаетесь с понятием идентичности типа в .NET. Который утверждает, что тип не просто идентифицируется пространством имен и именем типа, но также и сборкой, из которой он пришел. Это очень сильная анти-DLL Hell countermeasure, вид, с которым вы обходитесь здесь, используя типы, которые не будут доступны в целевой архитектуре.

И холодный факт состоит в том, что в библиотеке 4.5 PCL тип StreamingContext живет в сборке System.Runtime.Serialization.dll. Приложение, предназначенное для рабочего стола, будет использовать одно из mscorlib.dll. Это не переадресованный тип, он дублируется. Сборка System.Runtime.Serialization.dll - это небольшая сборка с явным намерением изолировать эти зависимости и предотвратить DLL-ад.

Kaboom во время выполнения, он видит метод с аргументом с неправильным идентификатором типа.