Страницы

Поиск по вопросам

воскресенье, 22 декабря 2019 г.

Возможна ли сериализация несериализуемого объекта?

#c_sharp #сериализация


При попытке сериализовать такой объект программа валится с ошибкой:


  Тип CookComputing.XmlRpc.XmlRpcStruct в сборке CookComputing.XmlRpcV2,
  Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d6e17aa302004d не
  отмечен как сериализуемый.


можно ли как то обойти это и сериализовать объект такого типа?
У меня нет доступа к изменению свойств этого типа.

Буду рада, если мне подскажете например другие способы распаковать и увидеть то что
пришло от сервера

[XmlRpcUrl("https://blabala.com/rpc")] // описание методов
public interface Trac : IXmlRpcProxy            
{       
    [XmlRpcMethod("ticket.get")]  //
    object[] get(int id);

    [XmlRpcMethod("ticket.getActions")]  //
    object[] getActions(int id);
}

public partial class DHL : Form
{
    public DHL()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        int id = 6;                  
        get(id);
    }

    private void get(int id)
    {
        Trac proxy;
        string user = "uzer";
        string password = "parol";
        proxy = XmlRpcProxyGen.Create();
        proxy.Credentials = new System.Net.NetworkCredential(user, password);
         object[] arr = proxy.get(id);
         BinaryFormatter formatter = new BinaryFormatter();
        using (FileStream fs = new FileStream("arr.dat", FileMode.OpenOrCreate))
          {
              formatter.Serialize(fs, arr);// тут и ошибка, что Тип CookComputing.XmlRpc.XmlRpcStruct
в сборке CookComputing.XmlRpcV2, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d6e17aa302004d
не отмечен как сериализуемый.
          }
    }

    private void button4_Click(object sender, EventArgs e)
    {
        int id = 6;            
        getActions( id);
    }

    private void getActions(int id)
    {
        Trac proxy;
        string user = "uzer";
        string password = "parol";
        proxy = XmlRpcProxyGen.Create();
        proxy.Credentials = new System.Net.NetworkCredential(user, password);
        object[]  arr = proxy.getActions(id);
        BinaryFormatter formatter = new BinaryFormatter();
        using (FileStream fs = new FileStream("arr.dat", FileMode.OpenOrCreate))
        {
        formatter.Serialize(fs, arr);//а тут нет такой ошибки
        }
    }
}

    


Ответы

Ответ 1



Нашел решение на EnSO, далее вольный перевод: Можно создать serialization surrogate. Например, у нас есть такой класс public class Person { public string Name { get; set; } public int Age { get; set; } public DriversLicense License; } // An instance of this type will be part of the object graph and will need to be // serialized also. public class DriversLicense { public string Number { get; set; } } Необходимо создать суррогат для каждого объекта в графе объектов. Для этого необходимо реализовать интерфейс ISerializationSurrogate public class PersonSurrogate : ISerializationSurrogate { /// /// Manually add objects to the store. /// public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { Person person = (Person) obj; info.AddValue("Name", person.Name); info.AddValue("Age", person.Age); info.AddValue("License", person.License); } /// /// Retrieves objects from the store. /// /// public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { Person person = (Person)obj; person.Name = info.GetString("Name"); person.Age = info.GetInt32("Age"); person.License = (DriversLicense) info.GetValue("License", typeof(DriversLicense)); return person; } } public class DriversLicenseSurrogate : ISerializationSurrogate { /// /// Manually add objects to the store. /// public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { DriversLicense license = (DriversLicense)obj; info.AddValue("Number", license.Number); } /// /// Retrieves objects from the store. /// /// public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { DriversLicense license = (DriversLicense)obj; license.Number = info.GetString("Number"); return license; } } Далее тебе нужен IFormatter, который знает о твоих суррогатах им им нужно инициализировать SurrogateSelector: private static void SerializePerson(Person person) { if (person == null) throw new ArgumentNullException("person"); using (var memoryStream = new MemoryStream()) { //Configure our surrogate selectors. var surrogateSelector = new SurrogateSelector(); surrogateSelector.AddSurrogate(typeof (Person), new StreamingContext(StreamingContextStates.All), new PersonSurrogate()); surrogateSelector.AddSurrogate(typeof (DriversLicense), new StreamingContext(StreamingContextStates.All), new DriversLicenseSurrogate()); //Serialize the object IFormatter formatter = new BinaryFormatter(); formatter.SurrogateSelector = surrogateSelector; formatter.Serialize(memoryStream, person); //Return to the beginning of the stream memoryStream.Seek(0, SeekOrigin.Begin); //Deserialize the object Person deserializedPerson = (Person) formatter.Deserialize(memoryStream); } } Если необходимо сериализовать защищенные и приватные поля, то задача может решаться несколько сложнее. Подозреваю, что придется пользоваться рефлексией и ручками брать\присваивать значения из недоступных свойств... Еще интересное мнение по этому поводу нашел: Суть в том, что не всегда-это реализуемо. Например, контролы Windows Forms хранят хэндлы ОС=> при десериализации на другой машине все скорее всего упадет. Наверное, можно и это учесть с помощью WinApi, но это уже изврат. Рихтер в своей книге хорошо описывает процесс сераиализации несериализуемых объектов. В том числе приводится пример с суррогатами.

Ответ 2



Нашла решение своей задачи с помощью DataTable object[] arr = proxy.get(id); //момент получения данных DataTable dt = new DataTable(); XmlRpcStruct arr3 = (XmlRpcStruct)arr[3];//проблема у меня была с выводом 3 его элемента объекта, поэтому его и преобразовываем XmlRpcStruct[] arr33 = new XmlRpcStruct[1]; arr33[0] = arr3; dt = StructArrayToDT(arr33);//преобразуем в DataTable //DA.Fill(dt); dataGridView1.DataSource = dt;//полученный DataTable можно вывести в DataGrid textBox1.Text = textBox1.Text + arr[0] + "\r\n" + arr[1] + "\r\n" + arr[2] + "\r\n";// тут выводим 0-2 члены объекта, с которыми не было проблем BinaryFormatter formatter = new BinaryFormatter();//можно сериализовать полученный DataTable using (FileStream fs = new FileStream("arr.dat", FileMode.OpenOrCreate)) { formatter.Serialize(fs, dt); } public static DataTable StructArrayToDT(XmlRpcStruct[] data) //метод который из XmlRpcStruct[] делает DataTable { DataTable dt = new DataTable(); if (data.Length == 0) { return dt; } // do columns foreach (DictionaryEntry d in data[0]) { dt.Columns.Add(d.Key.ToString(), typeof(object)); } foreach (XmlRpcStruct xmlstruct in data) { DataRow dr = dt.NewRow(); foreach (DictionaryEntry d in xmlstruct) { try { dr[d.Key.ToString()] = d.Value; } catch (Exception ex) { // handle errors } } dt.Rows.Add(dr); } return dt; }

Комментариев нет:

Отправить комментарий