Бинарная десериализация .Net - PullRequest
4 голосов
/ 05 января 2012

Я использую BinaryFormatter для десериализации файла из другого приложения. Они совместно используют базовые библиотеки, и большинство типов, сериализованных в файле, известны.

Однако, есть также некоторые типы, совершенно неизвестные и не имеющие обновляемого соответствия. Я хочу иметь возможность отказаться от десериализации для этих случаев.

В настоящее время я использую BinaryFormatter, инициализированный с помощью SurrogateSelector и SerializationBinder, который я использую для обновления типов, затронутых изменениями пространства имен в последних версиях.

var formatter = new BinaryFormatter
{
    Context = streamingContext,
    SurrogateSelector = ss,
    Binder = new ProxiedRemappingSerializationBinder(),
    FilterLevel = TypeFilterLevel.Low
};

try
{
    var deserializedObject = formatter.Deserialize(contentsStream);
    ...
}

В частности, проблема возникает, когда внутри .NET Framework пытается установить значения в массиве известного интерфейса, но с неизвестным типом значения. Исключение, которое я получаю: «System.InvalidCastException: объект не может быть сохранен в массиве этого типа».

Так есть ли способ заставить процесс десериализации отбросить эти типы (и просто оставить нули) или даже как-то воздействовать на SerializationBinder, чтобы предотвратить это исключение?

Заранее спасибо

** РЕДАКТИРОВАТЬ **

Помимо трассировки стека, это типичная ошибка InvalidcastException. Я отлаживал в .NET Framework, проходя через BinaryFormatter, BinaryObjectReader и ObjectManager, и он завершается ошибкой на этапе исправления (когда он присваивает фактические значения экземплярам) в массиве. Разрыв в Array.cs, строка 516, в InternalSetValue (& elemref, значение); где возникает исключение.

Я использую Binder для изменения некоторых типов времени десериализации на те, которые известны моему приложению (более поздняя версия типа), или на фиктивный класс. Я понимаю, почему происходит исключение, в основном он пытается установить несовместимый тип объекта в массиве интерфейса.

Этот тип является прокси-типом, который я динамически генерировал для хранения информации об объекте, подобной этой реализации: http://holistictendencies.wordpress.com/2009/11/16/creating-proxies-in-for-round-tripping-unknown-objects-in-c-server-apps/ Итак, поскольку он не реализует интерфейс массива, он терпит неудачу. Я просто хочу, чтобы двигатель как-то отбрасывал эти случаи.

1 Ответ

1 голос
/ 01 февраля 2017

У меня была похожая проблема, когда мне нужно было BinaryFormatter.Deserialize () класс, для которого у меня не было информации о типе, но я хотел получить некоторые значения из свойств этого объекта.

Когда пришло время десериализации этого объекта, .NET выдавал исключение SerializationException, жалуясь на неизвестный тип сборки.

Я решил это, создав собственный класс с нужными мне свойствами (помеченный как Serializable), а затем создал другой класс, который наследуется от SerializationBinder:

public class MySerializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        if (assemblyName.Contains("namespace I don't have") && typeName.Contains("type info I don't have"))
                return typeof(MySubstitute);
        return Type.GetType($"{typeName}, {assemblyName}");
    }
}

[Serializable]
public class MySubstitute
{
    public string Name { get; set; }
    public string Title { get; set; }
}

Обратите внимание, что если это не тот тип, который я ищу, я просто возвращаю то, что было передано.

Затем, когда вы создаете BinaryFormatter, присвойте свойству связывателя экземпляр вашего нового настраиваемого связывателя:

 using (FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open))
 {
       BinaryFormatter bf = new BinaryFormatter()   
      {
            Binder = new MySerializationBinder ()
       };                     
       mySubstitute = (MySubstitute)bf.Deserialize(fs);           
       fs.Close();
 }
...