Десериализация из данных, полученных асинхронно - PullRequest
0 голосов
/ 22 сентября 2009

В моем приложении у меня есть три объекта коллекции, которые хранят данные. Данные, которые заполняют эти коллекции, загружаются из файла XML в Интернете.

Три класса данных очень просты, типичный пример приведен ниже:

[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "companies")]
public partial class CompanyList
{      
    private List<Company> itemsField = new List<Company>();

    [XmlElement("company", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public List<Company> Items
    {
        get { return this.itemsField; }
    }
}

[SerializableAttribute()]
[XmlTypeAttribute(AnonymousType = true)]
public partial class Company
{
    private int companyIdField;
    private string companyNameField;

    [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, ElementName = "companyid")]
    public int CompanyID
    {
        get { return this.companyIdField; }
        set { this.companyIdField = value; }
    }

    [XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, ElementName = "companyname")]
    public string CompanyName
    {
        get { return this.companyNameField; }
        set { this.companyNameField = value; }
    }
}

Чтобы загрузить данные для этих объектов из Интернета, я написал асинхронный веб-клиент, который будет принимать URI, загружать данные, а затем запускать обработчик событий с загруженными данными, передаваемыми в виде строки в DownloadCompleteEventArgs. При вызове конструктора для этого веб-клиента я передаю один из пустых объектов для десериализации данных в качестве параметра объекта - он передается между асинхронными методами через пользовательский класс.

Здесь я сталкиваюсь с трудностями. В обработчике событий я хочу взять строку и десериализовать ее в соответствующий объект. Однако, хотя десериализация работает нормально, исходный объект не изменяется - предположительно потому, что я работаю над копией объекта.

Я пытался передать ref в исходный конструктор и между пользовательскими классами, но компилятор не разрешил мне приводить тип к "ref object", и я хотел бы сохранить загрузку / десериализацию в Интернете Тип кода не зависит. Кроме того, у меня появляется «ощущение», что я сильно отклоняюсь от нормы, и на самом деле виноват мой выбор шаблона проектирования.

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

РЕДАКТИРОВАНИЕ: Добавление некоторого дополнительного контекста: мне нужно десериализовать строку XML в объект из асинхронного обратного вызова. Например, я мог бы сделать три вызова DownloadXMLAsync (), который является методом, который вызывает DownloadCompleted (DownloadCompletedEventArgs), когда это будет сделано. Каждый из трех вызовов возвращает данные для заполнения трех разных объектов. Как можно надежно передать ссылку на объект через асинхронные вызовы, чтобы метод DownloadCompleted () мог правильно заполнить нужный объект в каждом случае?

Я попытался определить DownloadXMLAsync (ref object objectToPopulate), а затем передать objectToPopulate в объекте состояния в вызове HttpWebRequest.BeginGetResponse (), но я получаю "не могу преобразовать из ref TicketSpaceSiteServer.CompanyList 'в' ref объект».

Ответы [ 2 ]

2 голосов
/ 22 сентября 2009

Я использую следующий код для создания нового объекта из строки XML:

public class Util
{
    static private T Load<T>(string xml)
    {
        T t;

        XmlSerializer serializer = new XmlSerializer(typeof(T));
        try
        {
            System.Text.ASCIIEncoding  encoding=new System.Text.ASCIIEncoding();
            Byte[] bytes = encoding.GetBytes(xml);
            using (MemoryStream ms = new MemoryStream(bytes))
            {
                t = (T)serializer.Deserialize(ms);
            }
        }
        catch (Exception ex) 
        {
            throw ex; // This part is for debugging
        }

        return t;
    }
}

Используйте это как:

MyType my = Util.Load<MyType>(myXmlString);
0 голосов
/ 13 октября 2009

В итоге я выбрал простой вариант. Асинхронный обратный вызов DownloadCompleted вызывается всякий раз, когда загружается файл XML. Я не передаю ссылку на объект для заполнения, но вместо этого анализирую XML, чтобы определить, какие данные объекта содержатся в нем, а затем использую эти знания для правильного возврата объекта правильного типа, т.е.

        if (xml.StartsWith("<?xml version=\"1.0\"?>\n<companies>"))
        {
            return LoadFromXmlString<CompanyList>(xml);
        }
        else if (xml.StartsWith("<?xml version=\"1.0\"?>\n<shows>"))
        {
            return LoadFromXmlString<ShowList>(xml);
        }
        else if (xml.StartsWith("<?xml version=\"1.0\"?>\n<performances>"))
        {
            return LoadFromXmlString<PerformanceList>(xml);
        }

Затем в родительском классе:

    void wd_DownloadComplete(object sender, DownloadCompletedEventArgs e)
    {
        object foo = SerializationHelper.LoadFromXmlString(e.DownloadedString);
        switch (foo.GetType().ToString())
        {
            case "TicketSpaceSiteServer.CompanyList":
                companies = foo as CompanyList;
                break;
            case "TicketSpaceSiteServer.PerformanceList":
                performances = foo as PerformanceList;
                break;
            case "TicketSpaceSiteServer.ShowList":
                shows = foo as ShowList;
                break;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...