2012-07-06 8 views
8

私は以下のコードで問題を単純化して再現しました。引数1: 'System.Collections.ObjectModel.Collection'から 'System.Collections.ObjectModel.Collection'に変換できないC#コレクションをインターフェイスのコレクションとして渡す

この問題を引き起こした設計上の決定の背景: "IFruit"を扱うためのWebサービスを作成しましたが、私が理解しているようにSOAPとエンドポイントのバインディングの性質上、IFruitの明示的な実装でメソッドを作成しました。ビジネスレイヤーでは、果物の特定の実装ごとに別々のメソッドを作成すると、まず重複したコードが多く発生し、ビジネスとサービスレイヤーを強く結び付けると、後でWebサービスで新しいIFruitタイプを受け入れるには、 (冗長コードの別のコピーを追加する)。この設計は、私が過去にJavaを使ってうまく実装したものですが、C#のインタフェースは私を捨てるだけの違いがあるようです。お知らせ下さい。

public interface IFruit{ 
    public string TakeBite(); 
} 

public Apple : IFruit{ 
    public string TakeBite(){ 
     return "tasty bite of apple"; 
    } 
} 

public void EatFruit(Collection<IFruit> fruits){ 
    foreach(var fruit in fruits){ 
     Console.WriteLine(fruit.TakeBite()); 
    } 
} 

public void EatApples(Collection<Apple> apples){ 
    this.EatFruit(apples); 
} 

答えて

9

IEnumerable<IFruit>

public void EatFruit(IEnumerable<IFruit> fruits) 
{ 
    foreach (var fruit in fruits) 
    { 
     Console.WriteLine(fruit.TakeBite()); 
    } 
} 

にインタフェースIEnumerable<out T>を受け入れるためにあなたのEatFruit方法を変更してみてください、それがout修飾子が付いているので、共分散をサポートしています。 Collection<T>にはこのような修飾語句は付けられていません。

+0

ありがとうございます。これがコンパイルされます。今私の単体テストを更新する。 – YouGotCSharpInMyJava

1

これは、共分散と呼ばれます。
ただし、変更可能なコレクションでは不可能です。

そうでない場合は、EatFruit

fruits.Add(new Orange()); 

を書くことができます。ネット4は、あなたがIEnumerable<IFruit>に変更することができ、それが動作しますので、REAS専用のインターフェイスのための共分散をサポートしています。

+0

オレンジがIFruitを実装すると仮定すると、そこに問題がありますか? – Charleh

+1

@Charleh: 'fruits'は実際には' Collection 'です。それは 'オレンジ'を保持することはできません。 – SLaks

+0

果物はコレクターだったので、IFruitを実装するすべてのタイプを含めることができると思いましたか? – Charleh

0

脇のIEnumerableを使用してからコレクションをチェックし入力することができ(ビット恐ろしいが、それは動作するはずです):

public void EatApples(Collection<IFruit> fruit) 
    var col = new Collection<IFruit>(); 

    fruit.Where(x => x is Apple).ToList().ForEach(x => col.Add(x)); 

    this.EatFruit(col); 
} 

私が代わりにIEnumerableをを使用したいけれども - あなたがリファクタリングすることができない場合は、これは単なるオプションです。 P

(!あなたはそれを作るとして、それはタイプセーフとしてです)

+0

それは2倍の仕事をするでしょう - リストを作成してくださいそれぞれをコレクションに追加します。良いことをする: 'foreach(var x in fruit.OfType ()){col.Add(x); } '。 –

+0

ええ、真実 - 私はそれが演奏されるとは言いませんでした(そして私はあまりにも恐ろしい言及をしました!):D – Charleh

0

シンプルなソリューション:

public void EatApples(Collection<Apple> apples){ 
    this.EatFruit(
      new Collection<IFruit>(
       apples.Cast<IFruit>() 
     ) 
    ); 
} 

より良い解決策:C#4で導入された共分散を使用してください:Kevinの回答

関連する問題