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 во время выполнения, он видит метод с аргументом с неправильным идентификатором типа.