从异步接收的数据反序列化

时间:2009-09-21 21:46:51

标签: c# .net asynchronous

在我的应用程序中,我有三个存储数据的集合对象。填充这些集合的数据将从Web上的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; }
    }
}

为了从Web下载这些对象的数据,我编写了一个异步Web客户端,它将获取URI,下载数据,然后触发事件处理程序,下载的数据作为字符串在DownloadCompleteEventArgs中传递。在调用此Web客户端的构造函数时,我将要反序列化的数据的一个空对象作为对象参数传递 - 这是通过自定义类在异步方法之间传递的。

这是我遇到困难的地方。在事件处理程序中,我想获取字符串并将其反序列化为适当的对象。但是,尽管反序列化工作正常,但原始对象不会被修改 - 大概是因为我正在处理对象的副本。

我已经尝试将refs传递给原始构造函数和自定义类之间,但编译器不会让我将我的类型转换为“ref object”,并且我想保留web下载/反序列化代码类型不可知。另外,我有一种'感觉',我正在偏离轨道,实际上我选择的设计模式是错误的。

总而言之,创建一个'helper'类的最佳方法是什么,该类可以从适当的异步下载的xml数据字符串中填充不同类型的各种对象中的任何一个?

编辑: 添加一些进一步的上下文:我需要从异步回调中将XML字符串反序列化为对象。例如,我可能会对DownloadXMLAsync()进行三次调用,这是一个在完成后调用DownloadCompleted(DownloadCompletedEventArgs)的方法。三个调用中的每一个都返回数据以填充三个不同的对象。如何通过异步调用可靠地传递对象的引用,以便DownloadCompleted()方法可以在每种情况下正确填充正确的对象?

我试图限定DownloadXMLAsync(参照对象objectToPopulate),然后使objectToPopulate的状态对象的呼叫内HttpWebRequest.BeginGetResponse(),但我得到“无法从‘REF TicketSpaceSiteServer.CompanyList’转换到“REF对象'。”

2 个答案:

答案 0 :(得分:2)

我使用以下代码从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);

答案 1 :(得分:0)

最后我选择了简单的选项。每当下载XML文件时,都会调用DownloadCompleted异步回调。我没有传递对要填充的对象的引用,而是解析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;
        }
    }