2016-08-19 6 views
0

FirstOrDefaultの予想される動作は、述語と一致するアイテムを見つけた後、遅延の評価を行うためのものです。ただし、次の例では、述語が最初の項目に一致してもコレクション全体が列挙されます。C#Reactive Extensions(rx)FirstOrDefaultは、コレクション全体を列挙します

void Main() 
{ 
    var entities = Observable.Defer(() => GetObservable().Concat()); 
    Entity result = null; 
    var first = entities.FirstOrDefaultAsync(i => i.RowId == 1).Subscribe(i => result = i); 
    result.Dump(); 
    buildCalled.Dump(); 
} 

// Define other methods and classes here 

public IEnumerable<IObservable<Entity>> GetObservable() 
{ 
    var rows = new List<EntityTableRow> 
    { 
     new EntityTableRow { Id = 1, StringVal = "One"}, 
     new EntityTableRow { Id = 2, StringVal = "Two"}, 
    }; 
    return rows.Select(i => Observable.Return(BuildEntity(i))); 
} 

public int buildCalled = 0; 
public Entity BuildEntity(EntityTableRow entityRow) 
{ 
    buildCalled++; 
    return new Entity { RowId = entityRow.Id, StringVal = entityRow.StringVal }; 
} 

public class Entity 
{ 
    public int RowId { get; set; } 
    public string StringVal { get; set; } 
} 

public class EntityTableRow 
{ 
    public int Id { get; set; } 
    public string StringVal { get; set; } 
} 

(友好コードシュロモためのおかげで)これは期待される動作ですか?本当に必要になるまで、オブジェクト(この場合は特に建物)の列挙を延期する方法はありますか?

+0

http://stackoverflow.com/help/mcveを提供していただけますか? – Shlomo

答えて

2

次はあなたが持っているものにLinqpadフレンドリーコードと同等です:

void Main() 
{ 
    var entities = Observable.Defer(() => GetObservable().Concat()); 
    Entity result = null; 
    var first = entities.FirstOrDefaultAsync(i => i.RowId == 1).Subscribe(i => result = i); 
    result.Dump(); 
    buildCalled.Dump(); 
} 

// Define other methods and classes here 

public IEnumerable<IObservable<Entity>> GetObservable() 
{ 
    var rows = new List<EntityTableRow> 
    { 
     new EntityTableRow { Id = 1, StringVal = "One"}, 
     new EntityTableRow { Id = 2, StringVal = "Two"}, 
    }; 
    return rows.Select(i => Observable.Return(BuildEntity(i))); 
} 

public int buildCalled = 0; 
public Entity BuildEntity(EntityTableRow entityRow) 
{ 
    buildCalled++; 
    return new Entity { RowId = entityRow.Id, StringVal = entityRow.StringVal }; 
} 

public class Entity 
{ 
    public int RowId { get; set; } 
    public string StringVal { get; set; } 
} 

public class EntityTableRow 
{ 
    public int Id { get; set; } 
    public string StringVal { get; set; } 
} 

次へGetObservableを変更する場合は、あなたが希望する結果を得るでしょう:

public IObservable<IObservable<Entity>> GetObservable() 
{ 
    var rows = new List<EntityTableRow> 
    { 
     new EntityTableRow { Id = 1, StringVal = "One"}, 
     new EntityTableRow { Id = 2, StringVal = "Two"}, 
    }; 
    return rows.ToObservable().Select(i => Observable.Return(BuildEntity(i))); 
} 

をそれが表示されますConcat<TSource>(IEnumerable<IObservable<TSource>>)の実装は、列挙可能性を評価することに熱心であるが、Concat<TSource>(IObservable<IObservable<TSource>>)およびToObservable<TSource>(IEnumerable<TSource>)の実装は、怠惰を適切に維持する。理由を知っているとは言えません。

+0

IEnumerableをIObservableに変換すると、確かに熱心な読み込みが停止しました。行動の違いを説明する書類はないようです。私はこの投稿への参照を使って[repoに関する問題](https://github.com/Reactive-Extensions/Rx.NET/issues/267)を作成しました。助けてくれてありがとうShlomo – kmusick

+2

@kmusick - これが私たちが友達にモナドを混ぜさせない理由です。あなたがそれを避けることができるならば、 'IEnumerable 'と 'IObservable 'を混ぜてはいけません。あなたの 'GetObservable'メソッドは単に' IObservable 'を返し、' return'は 'return rows.ToObservable()。Select(i => BuildEntity(i));'でなければなりません。 – Enigmativity

+2

@Enigmativity Amen。 –

関連する問題