2009-12-08 16 views
6

を返すために、式の型を変換することができませんなぜこの作業を行います。一覧 - タイプ

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(); 
} 

答えて

10

db.Coupons ... ToListメソッド()はIList<Coupon>ではなく、IList<ICoupon>を返すため。 C#3は、一般的な分散をサポートしていないためIList<Coupon>IList<ICoupon>から派生しません。 (C#4は、一般的な分散をサポートしていますが、それはまだこのような場合には派生しません。誰IList<ICoupon>を受信すると、それにSomeEvilTypeThatImplementsICouponを詰め込むことを試みることができることを考えてみましょう。しかし、SomeEvilTypeThatImplementsICouponは、クーポンから派生していないためIList<Coupon>はそれを受け入れることができませんでした。若干異なる文脈ではあるものの、この兌換問題の議論のためのhttp://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.htmlを参照してください、そしてエリックリッペルトの記事はそこからリンクされます。)

(あなたの最初のスニペットは、対照的に、明示的にその何かを含めることができますList<ICoupon>を構築ICouponを実装し、そのリストにいくつかのクーポンオブジェクトを置きます。受信機はそれにSomeEvilTypeThatImplementsICouponを突くことを決定した場合は、リストがどのICouponを保持するために建てられたので、今、すべてが、うまくありますだけでなく、実際のクーポンオブジェクト。)

0

IQueryable<ICoupon>IList<ICoupon>に由来していません。

+0

... – Martin

+0

申し訳ありませんが、それを見ていません。 return文を 'var x = _db ...;'と 'return x'にします。 'var x 'の上にカーソルを置くと、VSがどのようなタイプであるかを確認します。 –

+0

は式の型を変換できませんリストを返す型IList Martin

4

それは暗黙のうちに<ICoupon>の一覧を表示するリストに<クーポン>をキャストすることはできません。これを試してみてください:

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

Typo:_db.Coupons.Where(x => x.Site.slug == siteSlug).Select(x =>新しいクーポン(x.id))キャスト ().ToList()...しかし、感謝、それは動作します。 – Martin

+0

これらのいずれかがうまくいくはずです。キャストはIQueryableとIEnumerableの両方のインターフェイスにあり、リストに変換する前または後でキャストすることができます。それはほとんど違いはありません。 – fyjham

+0

.Cast <>()はIEnumerableを返します。そのため、.Cast <>()の後に.ToList()を使用する必要があります。 – Martin

0

コンパイラはSelectとしてジェネリック型引数に、ICoupon、およびないCouponを推測するためです。だからではなく(それはすべての項目を反復処理する必要があるため、あまり効率的ではない)他の人が提案したようSelect後の明示的なキャストの、あなたも正しいSelect generic typesを指定することにより、暗黙的キャスト(またはより正確に分散)を使用することができます。

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

そこに.ToList()があります(あなたがCouponsコレクションの適切なタイプの?を交換する必要があります。)