接口列表与派生类型列表 - 无法将表达式类型转换为返回类型

时间:2009-12-08 01:43:17

标签: c# linq interface

为什么这样做:

public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
    var coupons = _db.Coupons.Where(x => x.Site.slug == siteSlug)
                     .Select(x => new Coupon(x.id));

    var list = new List<ICoupon>();
    foreach (var coupon in coupons)
    {
        list.Add(coupon);
    }

    return list;
}

但这确实不起作用(错误 - 无法将表达式转换为返回类型):

public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
    return _db.Coupons.Where(x => x.Site.slug == siteSlug)
                      .Select(x => new Coupon(x.id)).ToList();
}

4 个答案:

答案 0 :(得分:10)

因为db.Coupons ... ToList()返回IList<Coupon>而不是IList<ICoupon>IList<Coupon>并非源自IList<ICoupon>,因为C#3不支持通用差异。 (C#4确实支持通用方差,但在这种情况下它仍然不会得到。考虑到收到IList<ICoupon>的人可能会尝试将SomeEvilTypeThatImplementsICoupon填充到其中。但是IList<Coupon>无法接受因为SomeEvilTypeThatImplementsICoupon不是从优惠券派生的。请参阅http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html以讨论这个可兑换问题,尽管情况略有不同,并且Eric Lippert文章从那里链接。)

(相比之下,您的第一个代码段显式构造了一个List<ICoupon>,其中可以包含任何实现ICoupon的内容,然后将一些Coupon对象放入该列表中。现在,如果接收者决定将SomeEvilTypeThatImplementsICoupon戳入其中,一切都很好,因为List是为了保存任何ICoupon,而不仅仅是实际的Coupon对象。)

答案 1 :(得分:4)

它无法隐式地投射List&lt;优惠券&gt;列出&lt; ICoupon&gt;。试试这个:

public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
    return _db.Coupons.Where(x => x.Site.slug == siteSlug)
                      .Select(x => new Coupon(x.id)).Cast<ICoupon>().ToList();
}

这个的基本原因是,如果您有一个class FancyCoupon : ICoupon,并试图将其放入List<Coupon>,那么它会失败,因为FancyCoupon不是来自优惠券(只有ICoupon)但是它应该适用于List<ICoupon>。因此,乍一看它看起来应该能够使用一个作为另一个,这两种类型之间存在相当重要的差异。

演员调用基本上遍历列表并对每个列表进行类型转换以获得新列表(由于性能原因,在引擎盖下有更多内容,但出于实际目的,您可以这样想。)

(已从评论中修复)

答案 2 :(得分:0)

IQueryable<ICoupon>不是来自IList<ICoupon>

答案 3 :(得分:0)

这是因为编译器在ICoupon中推断Coupon而不是Select作为泛型类型参数。因此,不是在其他人提出的Select之后进行显式强制转换(因为它需要迭代所有项目而不是太有效),您也可以通过指定正确的{{{}来使用隐式强制转换(或者更正确的方差)。 3}}:

public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
    return _db.Coupons.Where(x => x.Site.slug == siteSlug)
                  .Select<?, ICoupon>(x => new Coupon(x.id)).ToList();
}

(您需要将?替换为Coupons集合的相应类型。)