#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; }
Комментариев нет:
Отправить комментарий