簡體   English   中英

從泛型方法返回泛型列表

[英]Returning Generic List from Generic method

我需要使用如下代碼從通用列表返回一個genericList templateFields ,如下所示:

public interface TestData
{
    string field { get; set; }
    string fieldName { get; set; }
    string type { get; set; }
}

private static IList<T> GETCG<T>(string test, string type) where T : Program.TestData
{
    XmlNodeList extractNode = xdoc.SelectNodes(
       @".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
    var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
    var templateFields = nodees.Cast<XmlNode>().Select(x => new
    {
        field = (String)x.Attributes["userName"].Value,
        fieldName = (String)x.Attributes["name"].Value
            .Substring(0, x.Attributes["name"].Value.IndexOf(':')),
        type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
            .IndexOf(':') + 1, 4)                          
    }).ToList();
}

return (T)Convert.ChangeType(templateFields, typeof(T));

返回時出現以下錯誤:

對象必須實現Iconvertible。

我確實了解templateFields並未實現IConvertible以使用ChangeType。 什么是返回templateFields的最佳方法

new()約束添加到T並使用以下代碼

private static IList<T> GETCG<T>(string test, string type) where T : TestData, new()
{
    XmlNodeList extractNode = xdoc.SelectNodes(@".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
    var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
    var templateFields = nodees.Cast<XmlNode>().Select(x => new T() //not anonymous type but T object
    {
        field = x.Attributes["userName"].Value,
        fieldName = (string)x.Attributes["name"].Value.Substring(0, x.Attributes["name"].Value.IndexOf(':')),
        type = x.Attributes["name"].Value.Substring(x.Attributes["name"].Value.IndexOf(':') + 1, 4)

    }).ToList();

    return templateFields;
}

我認為這里的問題是,當您select new { ... }時,您正在選擇一個匿名類型,然后Convert.ChangeType失敗,因為匿名類型僅包含public read-only屬性,並且未實現IConvertible 相反,我們要選擇一個新的T 但是為了做到這一點,我們還必須在T上包括一個new()約束 ,這意味着T必須具有默認的構造函數(以便我們可以創建它的實例)。

這樣,我們就不需要轉換任何東西,因為Select的結果就是List<T>

您還可以通過在一行中選擇IEnumerable<XmlNode>來減少某些代碼,而不是創建第二個變量並在第一個變量上進行cast

這樣的事情應該起作用:

private static IList<T> GETCG<T>(string test, string type) where T : TestData, new()
{
    IEnumerable<XmlNode> templateFieldNodes = xdoc
        .SelectNodes(".//mediaInstances/mediaInstance/properties/templateFields/templateField", 
            manager)
        .Cast<XmlNode>();

    return templateFieldNodes.Select(x => new T
    {
        field = (String)x.Attributes["userName"].Value,
        fieldName = (String)x.Attributes["name"].Value
            .Substring(0, x.Attributes["name"].Value.IndexOf(':')),
        type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
            .IndexOf(':') + 1, 4)
    }).ToList();
}

您聲明了接口TestData ,但未聲明實現它的任何類型。 您不能將偶然碰巧具有相同屬性的任何類型強制轉換為該接口。 您必須創建一個類或實現它的結構。 同樣,使用通常的.NET命名約定,接口名稱以大寫I開頭,屬性名稱具有PascalCase。

有了這些聲明...

public interface ITestData
{
    string Field { get; set; }
    string FieldName { get; set; }
    string Type { get; set; }
}

public class TestData : ITestData
{
    public string Field { get; set; }
    public string FieldName { get; set; }
    public string Type { get; set; }
}

你可以寫

private static IList<ITestData> GETCG(string test, string type)
{
    XmlNodeList extractNode = xdoc.SelectNodes(
        @".//mediaInstances/mediaInstance/properties/templateFields/templateField", manager);
    var nodees = new List<XmlNode>(extractNode.Cast<XmlNode>());
    var templateFields = nodees.Cast<XmlNode>().Select(x => (ITestData)new TestData {
        Field = (String)x.Attributes["userName"].Value,
        FieldName = (String)x.Attributes["name"].Value
            .Substring(0, x.Attributes["name"].Value.IndexOf(':')),
        Type = (String)x.Attributes["name"].Value.Substring(x.Attributes["name"].Value
            .IndexOf(':') + 1, 4)
    }).ToList();
    return templateFields;
}

請注意,該方法不是通用的。 要使.ToList()創建一個IList<ITestData> ,必須將新數據(ITestData)new TestData { ... }轉換為接口(ITestData)new TestData { ... }

問題是您是否仍然需要該接口,或者是否更喜歡直接使用該類。


如果仍然希望該方法是通用的,則必須告訴它T必須具有帶有new()約束的默認構造函數。 並且必須使用具體類型來調用該方法。 即,您不能使用該接口調用它,因為該接口沒有構造函數。

private static IList<T> GETCG<T>(string test, string type)
    where T : ITestData, new()
{
    ...
    var templateFields = nodees.Cast<XmlNode>().Select(x => new T {
       ...
    }).ToList();
    return templateFields;
}

然后打電話給

IList<TestData> var result = GETCG<TestData>("hello", "world");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM