从IObservable通过LINQ创建一个匿名对象?

时间:2014-08-10 09:58:40

标签: c# json linq system.reactive

我继承了一个通过JSON访问远程数据的拜占庭API,查询本身是通过TPL处理的,由于我不会进入的原因是支持我进入角落。

所以,我有一个IObservable订阅,我这样查询;

mcSub.Take(1).Subscribe(x => x.Markets.ForEach(i => i.Prices.AvailableToBuy.ForEach(t => tabPanel.textBox1.AppendText(i.Id + " Back \t" + t.Size + " @ " + t.Price))));

显然Markets和AvailableToBuy是列表,我的问题是 - 我如何创建一个LINQ查询/对象来提取i.Id,t.Size和t.Price?

2 个答案:

答案 0 :(得分:1)

我相信你可以这样做,在一个集合中扁平两次(一旦市场,然后价格),所有价格:

//get all prices available to buy:
var pricesAvailableToBuy = mcSub.SelectMany(x => x.Markets)
                           .SelectMany(y => y.Prices.AvailableToBuy)
                           .Select(p => new { p.Id, p.Size, p.Price });

这为您提供了mcSub所有市场的所有价格,而您的初始报表仅适用于一个市场项目(这也取决于它的名称 - 如果它是关于消费者工作者的话)任务/线程然后它是有道理的。)

或者,类似的表述:

var pricesAvailableToBuy = mcSub.SelectMany(x => x.Markets.SelectMany(y => y.Prices.AvailableToBuy))
                           .Select(p => new { p.Id, p.Size, p.Price });

答案 1 :(得分:1)

纬。

这是一个令人讨厌的鸣喇叭订阅/查询blob。让我们看看我们是否可以稍微清理一下......我看到你从mcSub拿到1并订阅它,所以我会假设它是一个可观察的数组?

让我们先假装一些我可以参考的类型(我会尽力从你的样本中推断出来):

首先,数据项:

public class Thing 
{
    public List<Market> Markets {get; set;}
}
public class Market
{
    public Price Prices {get; set;}
}
public class Price
{
    public List<AvailablePrice> AvailableToBuy {get; set;}  
}
public class AvailablePrice
{
    public string Id {get; set;}
    public int Size {get; set;}
    public decimal Price {get;set;}
}

接下来,会产生IEnumerable<IObservable<Thing>>的东西,我会一起劈砍:

public IEnumerable<IObservable<Thing>> GetThingsObs()
{
    var rnd = new Random();
    return Enumerable.Range(0, 3).Select(_ => {
        return Observable.Create<Thing>(obs =>
        {
            var things = Enumerable.Range(0, 3).Select(i => new Thing() 
            { 
                Markets = Enumerable.Range(0, 3).Select<int, Market>(x => 
                {                   
                    return new Market()
                    {
                        Prices = new Price
                        {
                            AvailableToBuy = Enumerable.Range(0, 3)
                                .Select(y => new AvailablePrice { Id = string.Format("{0}:{1}:{2}", i, x, y), Size = rnd.Next(0, 10), Price = rnd.Next(0, 20) })
                                .ToList()
                        }
                    };
                }).ToList()
            });
            foreach(var thing in things)
                obs.OnNext(thing);

            // this bit is important, but I'll get back to it later
            obs.OnCompleted();
            return Disposable.Empty;
        });
    });
}

好的,既然我们已经有了某些东西(我希望)有点映射到您的数据,那就让我们来查询吧!

如果已知可观察物完成(我上面的位置被掩盖了),您可以合理安全地将IObservable<T>转换为IEnumerable<T> - 如果它完成,这基本上会挂起,所以要小心!

var mcSub = GetThingsObs();
var query = 
    // for each observable
    from obs in mcSub   

    // this replaces your subscribe calls, but the observable MUST complete
    // for this to return properly!         
    from thing in obs.ToEnumerable()

    // After that, it's just multiple SelectManys 
    // (which is what the nested 'from x in y' calls get translated into)

    // For each market
    from market in thing.Markets
    // for each price thingy
    from price in market.Prices.AvailableToBuy
    // select out your stuff
    select new { price.Id, price.Size, price.Price };

这是我可以从您提供的样本中做出的最佳猜测 - 如果您可以提供更多信息/详细信息,如果这对您不起作用,我会再拍一次。