#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 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); } ///store. /// /// 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 public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) { DriversLicense license = (DriversLicense)obj; info.AddValue("Number", license.Number); } ///store. /// /// 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; }
Комментариев нет:
Отправить комментарий