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

Mar*_*tin 6 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

ito*_*son 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,而不仅仅是实际的优惠券对象.)