Сериализация / десериализация словарянужен в C ++ / CLI при внедрении dll в другой процесс - PullRequest
0 голосов
/ 05 мая 2011

Мне нужно сериализовать массив объектов array<object^>^ в C ++ / CLI, который содержит один intPtr и словарь Dictionary<IntPtr,ObjectInfo>, где ObjectInfo - некоторый пользовательский класс. Он сериализуется правильно, но при десериализации выдает эту ошибку:

"System.Runtime.Serialization..SerializationException:Unable

для загрузки типа System.Collections.Generic.Dictionary'2 [[System.IntPtr, mscorlib, Version = 4.0.0.0" , Культурные = нейтральная, PublicKeyToken = ..............], [System.Collection.Generic.List'1 [[SharedObjects.ObjectInfo, SharedObjects, версия ....]] требует десериализации.

Я передаю array<object^>^ в Type->InvokeMember в качестве аргументов, и эти аргументы необходимо десериализовать перед передачей в InvokeMember.

Но он не работает во время десериализации.

Сериализация кода:

     void Serialize(Object^ obj)
     {
        if (obj == nullptr)
        {
           _length = 0;
           return;
        }

     // We could write directly to shared data through an UnmanagedMemoryStream, and
     // catch an error if not big enough. But then we don' get info about how much memory
     // we needed, so instead we write to a dynamically resizing MemoryStream first.

       MemoryStream^ memstream = gcnew MemoryStream();
       BinaryFormatter^ formatter = gcnew BinaryFormatter();
       formatter->Serialize(memstream, obj);
      _length = (int)memstream->Length;

      if (_length > sizeof(_data))
      {
          throw gcnew ApplicationException(String::Format("Not enough shared memory to transfer data (have {0} bytes, but {1} bytes required)", sizeof(_data), _length));
      }

      UnmanagedMemoryStream^ stream = gcnew UnmanagedMemoryStream(_data, _length, _length, FileAccess::Write);
      memstream->WriteTo(stream);
      memstream->Close();
      stream->Close();
   }

Код десериализации

  Object^ Deserialize()
  {
    if (_length == 0)
    {
       return nullptr;
    }

    UnmanagedMemoryStream^ stream = gcnew UnmanagedMemoryStream(_data, _length, _length, FileAccess::Read);
    BinaryFormatter^ formatter = gcnew BinaryFormatter();
    Object^ obj = formatter->Deserialize(stream);
    stream->Close();
    return obj;
  }

1 Ответ

0 голосов
/ 05 мая 2011

Я попробовал ваш код, и он отлично работает с настраиваемым сериализуемым классом.

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

Ваш код сериализации и десериализации находится в одной сборке? Возможно, у вас есть 2 сборки, ссылающиеся на разные версии вашей сборки, содержащие ваш собственный класс ShareObject.ObjectInfo.

Вот мой тестовый код:

using namespace System;
using namespace System::IO;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using namespace System::Runtime::Serialization::Formatters::Binary;

System::Byte* _data;
int _length;

void Serialize(Object^ obj)
{
  MemoryStream^ memstream = gcnew MemoryStream();
  BinaryFormatter^ formatter = gcnew BinaryFormatter();
  formatter->Serialize(memstream, obj);
  _length = (int)memstream->Length;

  UnmanagedMemoryStream^ stream = gcnew UnmanagedMemoryStream(_data, _length, _length, FileAccess::Write);
  memstream->WriteTo(stream);
  memstream->Close();
  stream->Close();
}

Object^ Deserialize()
{
  UnmanagedMemoryStream^ stream = gcnew UnmanagedMemoryStream(_data, _length, _length, FileAccess::Read);
  BinaryFormatter^ formatter = gcnew BinaryFormatter();
  Object^ obj = formatter->Deserialize(stream);
  stream->Close();
  return obj;
}

[SerializableAttribute]
ref class SerializableClass
{
public:
  IntPtr ptr;
  String^ string;
  List<SerializableClass^>^ list;
 };

int main(array<String ^> ^args)
{
  IntPtr ptr = Marshal::AllocHGlobal(1000);
  _data = (System::Byte*)ptr.ToPointer();

  array<SerializableClass^>^ arr = gcnew array<SerializableClass^>(2);
  for (int i = 0; i < arr->Length; i++)
  {
    SerializableClass^ c = gcnew SerializableClass();
    c->ptr = System::IntPtr(1234);
    c->list = gcnew List<SerializableClass^>();

    SerializableClass^ c2 = gcnew SerializableClass();
    c2->string = "Value";
    c->list->Add(c2);
    c->list->Add(c2);

    arr[i] = c;
  }

  Serialize(arr);

  array<SerializableClass^>^ deserializedClass = dynamic_cast<array<SerializableClass^>^>(Deserialize());

  return 0;
}
...