泛型,用于在C#中将WebRequest和解析概括为自定义对象

本文关键字:对象 自定义 和解 WebRequest 用于 中将 泛型 | 更新日期: 2023-09-27 17:59:59

一个架构问题。我用C#(Mono)做了很多WebRequest:s。以下是一个获取"WorkFlowSchemes"的方法如何声明的示例:

public void GetWorkFlowSchemes(
   Credientials credentials, 
   ServerDelegates.WorkFlowSchemesSuccessDelegate successDelegate, 
   ServerDelegates.ErrorDelegate errorDelegate)

然后,它有"硬编码"的值,用于从哪个url获取,哪个回调它调用的响应,以及在该回调中:解析到哪个类型。

我想让这个方法通用,不必为我所做的每种类型的调用编写X个非常相似的方法。相反,我想要这样的东西:

public void GetCustomPath<K>(
    Credientials credentials,
    Path pathToFetch,
    ServerDelegate<K>.SuccessDelegate successDelegate, //Generic delegate to return different types of parsed result
    ServerDelegates.ErrorDelegate errorDelegate) // no need to be generic

其中K是要返回的委托的类型,即WorkFlowScemes或WorkFlow。

在解析之前,这项工作编译得相当好。以前我这样分析它:

List<WorkFlowScheme> workFlowSchemeList = serverXmlParser.parseXmlToWorkFlowSchemeList(responseBody);

我更愿意概括WorkFlowList的另一种硬编码解析方法。parseXmlToWorkFlowSchemeList看起来像这样:

    public List<WorkFlowScheme> parseXmlToWorkFlowSchemeList (string xml)
    {
        XDocument doc = XDocument.Parse(xml);
        List<WorkFlowScheme> result = 
            (
                from x in doc.Element("workflowschemeList").Elements("workflowscheme")
                select new WorkFlowScheme().Setup(x)
                ).ToList();
        return result;
    }

where .Setup(x)是存储在每个类型中的帮助方法,用于将XElement值转换并存储为当前对象中的字符串。这就是我被卡住的地方。首先,我尝试制作一种通用方法:

public List<T> parseXmlToCustomObject<T> (string xml, String root, String key)
{
        XDocument doc = XDocument.Parse(xml);
        List<T> result = 
            (
                from x in doc.Element(root).Elements(key)
                select new T().Setup(x)
                ).ToList();
        return result;
}

"选择新T.Setup(x)"不适用于

  • 第一次,因为我无法创建"new T()"(编辑:已解决)
  • 第二个原因是编译器不知道在哪里可以找到Setup方法

有什么建议吗?

我还考虑过将我所有的对象解析为"ServerObject"的子类,以便更容易地调用.Setup,但不知道如何将其与泛型合并。

编辑:到目前为止我得到的是:

public void GetCustomListObject<T>(Account account, String path, RequestStateGen<List<T>>.SuccessDelegate successDelegate, ServerDelegates.ErrorDelegate errorDelegate)
        where T : ServerObject, new()
    {
        var request = getGetRequest(account, path);
        RequestStateGen<List<T>> state = new RequestStateGen<List<T>>();
        state.Request = request;
        IAsyncResult result =
            request.BeginGetResponse(new AsyncCallback(onGetWorkFlowSchemes), state);
        //setupTimeOut(result, state);
        string responseBody = extractResponseAndCallDelegateOnError(request, result, errorDelegate);
        if (responseBody != null)
        {
            List<T> parsedObject = serverXmlParser.parseXmlToCustomObject<T>(responseBody);
            if (parsedObject != null)
            {
                successDelegate(parsedObject);
            }
        }
    }

解析方法:

public List<T> parseXmlToCustomObject<T> (string xml)
        where T : ServerObject, new()
    {
        XDocument doc = XDocument.Parse(xml);
        List<T> result = 
            (
                from x in doc.Element("workflowschemeList").Elements("workflowscheme")
                select new T().Setup(x)
                ).ToList();
        return result;
    }

其中ServerObject是包含.Setup的所有自定义对象类的基本对象。我现在得到的错误是在"List-result="行,错误为:

Cannot implicitly convert type `System.Collections.Generic.List<xxxx.Core.Network.Objects.ServerObject>' to `System.Collections.Generic.List<T>'

泛型,用于在C#中将WebRequest和解析概括为自定义对象

如果所有类都有一个公共的无参数构造函数,则可以将约束where T : new()添加到parseXmlToCustomObject中。这将消除第一个错误。

为了消除第二个错误,您必须创建一个包含Setup方法的接口或基类,并使所有类实现该接口或从该基类派生,然后将其添加为另一个约束:where T : ISetupable, new()(请原谅名称)

你的方法会是这样的:

public List<T> parseXmlToCustomObject<T> (string xml, String root, String key)
    where T : ISetupable, new()
{
        XDocument doc = XDocument.Parse(xml);
        List<T> result = 
            (
                from x in doc.Element(root).Elements(key)
                select new T().Setup(x)
                ).ToList();
        return result;
}

如果您无法确保所有类都有一个公共的无参数构造函数,那么您将不得不求助于工厂来创建对象。

您需要为泛型方法指定一个约束,以便生成T 的新实例

public List<T> parseXmlToCustomObject<T> (string xml, String root, String key) where T : new(){
[...]
}

[编辑]对于您的第二个问题:您需要有一个基类或接口,该基类或接口具有Setup()方法和对通用方法的另一个约束:

假设你有一个基类BaseClass,它有你的Setup()方法:

public List<T> parseXmlToCustomObject<T> (string xml, String root, String key) where T : BaseClass, new(){
[...]
}