C#Reactive Extensions(rx)FirstOrDefault枚举整个集合

时间:2016-08-19 15:58:17

标签: c# linq system.reactive rx-java lazy-evaluation

看起来FirstOrDefault的预期行为是在找到与谓词匹配的项目之后完成的,并且concat的预期行为是懒惰地评估。但是,即使谓词与第一个项匹配,以下示例也会枚举整个集合。

(感谢更友好的代码Shlomo)

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

这是预期的行为吗?有没有办法推迟对象的枚举(特别是在这种情况下的建筑物)直到真正需要?

1 个答案:

答案 0 :(得分: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>)的实现则恰当地保持了懒惰。我不能说我知道为什么。