Why does this work:
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;
}
But this does does not work (error – cannot convert expression type to return type):
public IList<ICoupon> GetCouponsForSite(string siteSlug)
{
return _db.Coupons.Where(x => x.Site.slug == siteSlug)
.Select(x => new Coupon(x.id)).ToList();
}
Because db.Coupons…ToList() returns an
IList<Coupon>rather than anIList<ICoupon>.IList<Coupon>does not derive fromIList<ICoupon>because C# 3 doesn’t support generic variance. (C# 4 does support generic variance, but it still won’t derive in this case. Consider that whoever receives anIList<ICoupon>could try to stuff a SomeEvilTypeThatImplementsICoupon into it. But anIList<Coupon>couldn’t accept that because SomeEvilTypeThatImplementsICoupon doesn’t derive from Coupon. See http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html for discussion of this convertibility issue albeit in a slightly different context, and the Eric Lippert articles linked from there.)(Your first snippet, by contrast, explicitly constructs a
List<ICoupon>, which can contain anything that implements ICoupon, and then puts some Coupon objects into that list. Now if the receiver decides to poke SomeEvilTypeThatImplementsICoupon into it, all is well, because the List was built to hold any ICoupon, not just actual Coupon objects.)