【问题标题】:Casting a list of children to a list of parent types将子列表转换为父类型列表
【发布时间】:2011-11-16 19:57:07
【问题描述】:

为简洁起见,我将在这里泛泛而谈。我有一个基类 - Review - 有一个孩子 - ShelfAwarenessReview。

我还有一个方法,接口需要它的签名:

public List<Review> GetReviews(string filePath)
        {
            XElement xmlDoc = XElement.Load(filePath);

            var dtos = from item in xmlDoc.Descendants("message")
                       select new ShelfAwarenessReview()
                       {
                           PubDate = item.Element("meta").Attribute("permlinkdate").Value,
                           Summary = item.Element("meta").Element("summary").Value,
                           Isbn = item.Element("BookInfo").Element("ISBN").Value
                       };

            List<Review> reviews = new List<Review>();
            reviews = dtos.ToList();

            return reviews;
        }

现在,我得到的错误是 List&lt;ShelfAwarenessReview&gt; 不能隐式转换为 List&lt;Review&gt;

我已经尝试了几种类型的投射 - 或者,至少我认为我这样做了 - 但它不起作用。我认为因为 ShelfAwarenessReview 是 Review 的一个孩子,所以这会起作用。毕竟,正如继承格言所说,“所有的烤面包机都是电器,但不是所有的电器都是烤面包机”......

我需要做什么才能获得 ShelfAwarenessReviews 列表以将方法作为其父类型(评论)的列表退出?

仅供参考,调用此方法的代码并不关心它获得的类型评论。后续代码将在任何东西上运行。

非常感谢。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    首先,您不需要创建一个空的List&lt;Review&gt; 然后忽略它:)

    这是最简单的解决方案:

    public List<Review> GetReviews(string filePath)
    {
        XElement xmlDoc = XElement.Load(filePath);
    
        var dtos = ...; // As before
    
        return dtos.Cast<Review>().ToList();
    }
    

    如果您使用的是 .NET 4 和 C# 4,由于泛型协方差适用于 IEnumerable&lt;T&gt; 但不适用于 List&lt;T&gt;,还有另一种选择:

    public List<Review> GetReviews(string filePath)
    {
        XElement xmlDoc = XElement.Load(filePath);
    
        IEnumerable<Review> dtos = ...; // As before
    
        return dtos.ToList();
    }
    

    注意dtos 类型的明确说明。查询表达式的类型为 IEnumerable&lt;ShelfAwarenessReview&gt;,但它可以隐式转换(在 C# 4 中)为 IEnumerable&lt;Review&gt;

    【讨论】:

    • 祝福你,好心的先生。该死。我需要更好地理解协方差和向上转换。你是第一个,所以你得到了我的批准。谢谢十亿。
    【解决方案2】:

    变化:

    reviews = dtos.ToList();
    

    收件人:

    reviews = dtos.Cast<Review>().ToList();
    

    问题在于 List 和 List 不是协变的。仔细想想就很容易理解:

    List<ShelfAwarenessReview> initial = new List<ShelfAwarenessReview>();
    List<Review> cast = (List<Review>)initial;
    
    // The underlying type is still List<ShelfAwarenessReview>.
    // SomeOtherReview inherits Review but not ShelfAwarenessReview
    // What will happen when I make the following call?
    cast.Add(new SomeOtherReview());
    

    【讨论】:

    • @JustinNiesnner 已经有很多人发布了答案,但感谢您的意见。不过,为努力 +1 :)。
    【解决方案3】:

    使用 Cast 转换为基本类型:

    return dtos.Cast<Review>().ToList();
    

    【讨论】:

    • 很多人已经发布了答案,但感谢您的意见。不过,为努力+1:
    【解决方案4】:

    Covariance的问题。对于您的特定问题,请尝试:

    return dtos.ToList().Cast<Review>();
    

    【讨论】:

    • 很多人已经发布了答案,但感谢您的意见。不过,为努力+1:
    【解决方案5】:

    您不能将列表投射到列表。假设你可以,可怕的事情会发生:

    List<String> list = new list<String>();
    list.Add("Hello");
    List<Object> list2 = List<Object>(list);
    list2.Add(12);
    

    嗯?我是否只是将一个整数添加到字符串列表中。这就是为什么你不能。您应该阅读有关协变和逆变的内容。

    【讨论】:

    • 我明白你的意思。谢谢你的例子。我知道有些事情是用 .NET 4 解决的 co/contra 方差。我确实需要更多地了解这一点。我还在寻找它的来源。再次感谢您的示例。
    【解决方案6】:
    List<Review> reviews = dtos.Cast<Review>().ToList();
    

    【讨论】:

      【解决方案7】:

      用这个

        List<Review> reviews = dtos.Cast<Review>().ToList(); 
      

      【讨论】:

        猜你喜欢
        • 2020-03-23
        • 1970-01-01
        • 1970-01-01
        • 2018-05-18
        • 1970-01-01
        • 1970-01-01
        • 2018-11-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多