2016-08-11 2 views
-1

私たちは、基本クラスを調整可能な派生クラスに拡張することによって、サードパーティのコードを適用することに取り組んでいます。 IEnumerableを返す1つのメソッドとは別に、すべてがうまく機能しています。IEnumerable .NETをオーバーライドします。

問題がどこにあるかを正確にテストするためにいくつかのsudoコードを作成しました。簡単な例で再作成できます。

この例では、メソッド内のコードブロックは決して呼び出されません。私たちはそこにブレークポイントを置いていますが、すぐにスローされる例外が追加されました。結果は常に同じです。デバッガは行をスキップします。

誰かが間違っていることを説明できますか?サードパーティのコードが単に機能しない可能性はありますか?

public class Test 
{ 
    public virtual IEnumerable GetList(Type type, string key) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class Test2 : Test 
{ 
    public override IEnumerable GetList(Type type, string key) 
    { 
     for (var x = 0; x <= 5; x++) 
     { 
      yield return x; 
     } 
    } 
} 

static void Main(string[] args) 
{ 
     var x = new Test2(); 
     var y = x.GetList(typeof(decimal), "test") as List<int>; 
} 

編集:いいえ、たくさんの問題がyieldキーワードでした。これはサードパーティの実装であるため、仮想メソッド内のコードのみを変更できます。結局、私はIEnumerableをループから戻ってくるのではなく、返すことになりました。

これにより、コードが第三者のライブラリ内で動作するようになりました。

+1

イテレータメソッドであるため、メソッドのコードは、列挙が開始されるまで実際には入力されません。 'foreach'で。 –

答えて

1

この式:メソッドから返されたイテレータの実行時の型がList<int>ないとList<int>にキャストすることはできませんので

x.GetList(typeof(decimal), "test") as List<int>; 

は...、何もせずに列挙nullを返します。

x.GetList(...)はかなりこれらすべてのyield returnステートメントをリッピングするために熱心に震えていますイテレータオブジェクトを返しますが、その後、あなたはそれが実際に代わりList<int>だかどうかを確認します。それがList<int>ではないことを知って、あなたはそれを脇に投げつけます。

明らかにこれはあなたの意思ではありませんでしたが、それはas演算子がC#でどのように動作するかです。

List<T>が必要な場合は、ToList()に電話する必要があります。 conversion operatorがなければ、C#の参照型のキャストは特別な処理をしません。このような場合、フレームワークはそれらを提供しません。私はそれが賢明だと思う。私は変換オペレータのファンではありません。 Equals()のように、あなたが少なくともそれを期待しているときには、あなたの腕を外している手を助ける手の一つになりがちです。

@Letseatunchが指摘する通り、IEnumerableではなくIEnumerable<int>を返すべきですが、それはoverrideなので、これはオプションではないと思います。しかし、それはそれでLINQyを行くために、あなたがCast<int>()か何かを追加する必要がありますことを意味します

var listofints = x.GetList(typeof(decimal), "test").Cast<int>().ToList(); 
6

あなたはList<int>

var y = x.GetList(typeof(decimal), "test") as List<int>; 

試しにキャストされているので、それはです:IEnumerableをはToListメソッドを持っているので、GetListのではなくIEnumerableの今IEnumerable<int>を返して

public class Test 
{ 
    public virtual IEnumerable<int> GetList(Type type, string key) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class Test2 : Test 
{ 
    public override IEnumerable<int> GetList(Type type, string key) 
    { 
     for (var x = 0; x <= 5; x++) 
     { 
      yield return x; 
     } 
    } 
} 
static void Main(string[] args) 
{ 
    var x = new Test2(); 
    var y = x.GetList(typeof(decimal), "test").ToList(); 
} 

注意。

+2

答えを完了するだけです... 'yield return'は、コレクションが列挙されるまで評価されないようにします(' .ToList() 'を呼び出します)。 – DanielS

1

これが原因で、鋳造のが、理由yieldない繰り返しを意味し、そしてどれもが、あらゆる種類のを強制しないが起こります繰り返し、何も起こらない。それを証明するために、直前のように、この

var y = x.GetList(typeof(decimal), "test");

  • 同じ間違った結果のように、鋳造せずに、同じコードを書き換えます。

例えば、それはあなたが 内のループを呼び出す必要があり、実施されたあるとして正しく、あなたの関数を使用するには:ToList()その力のように、

foreach(var i in x.GetList(typeof(decimal), "test")) {}

、または他のいくつかのメソッドを使用します列挙するコレクション。

今やあなたのメソッドが実際に呼び出されます。

+0

これは正確ではありません。たとえば、元のTest2.GetListが「新しいリストを返す」場合は(); yieldを使用する代わりに、キャストするとメソッドが呼び出され、var y = x.GetList(typeof(decimal)、 "test")と同じではありません。 – Letseatlunch

+0

@Letseatlunch:私の指摘は、問題は "キャスト"自体ではなく、列挙呼び出しの不足のためです。私たちはさまざまな方法でそれを達成することができます。 – Tigran

+0

あなたは問題が_itself_によって "キャスト"されているのではなく、リストにキャストされ、ヌルを返すので、問題が列挙できないことが正しいです。彼がキャスティングをしないとあなたが示したように、彼は彼の方法をそのまま使うことができます。 – Letseatlunch