Каков наилучший способ десериализации дженериков, написанных с другой версией подписанной сборки?
В других случаях было предложено просто добавить SerializationBinder, который удаляет версию из типа сборки. Однако при использовании универсальных коллекций типа, найденного в подписанной сборке, этот тип строго версионируется на основе своей сборки.
Вот что я нашел работы.
internal class WeaklyNamedAppDomainAssemblyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
ResolveEventHandler handler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomain.CurrentDomain.AssemblyResolve += handler;
Type returnedType;
try
{
AssemblyName asmName = new AssemblyName(assemblyName);
var assembly = Assembly.Load(asmName);
returnedType = assembly.GetType(typeName);
}
catch
{
returnedType = null;
}
finally
{
AppDomain.CurrentDomain.AssemblyResolve -= handler;
}
return returnedType;
}
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string truncatedAssemblyName = args.Name.Split(',')[0];
Assembly assembly = Assembly.Load(truncatedAssemblyName);
return assembly;
}
}
Тем не менее, изменение глобального процесса связывания кажется мне довольно опасным. Странные вещи могут произойти, если сериализация происходит в нескольких потоках. Возможно, лучшее решение - это выполнить некоторые регулярные выражения для typeName?
Редактировать: метод на основе строки не работает. Дженерики, очевидно, нуждаются в полном строго названном типе. Довольно отвратительно, если вы спросите меня.
3 ответа
Событие AssemblyResolve вызывается только в случае сбоя обычной привязки. Таким образом, все, что можно решить с помощью обычных методов, будет. Только операции десериализации могут вызвать событие, и у вас есть совершенно правильная стратегия для их устранения.
Я бы добавил обработчик события AssemblyResolve при запуске программы и оставил его там, а не добавил и удалил его. Это устраняет потенциальный источник проблем с многопоточностью.
Это должно ответить на ваш вопрос: SerializationBinder с List
При использовании универсальных типов в SerializationBinder.BindToType необходимо использовать слабые имена типов вместо полностью определенных имен типов.
Вместо того чтобы сериализовать всю коллекцию, не могли бы вы пройтись по ней и сериализовать каждый элемент отдельно? Тогда вы можете использовать подход SerilizationBinder.