颠倒嵌套IObservable的顺序

时间:2014-12-15 16:54:25

标签: c# system.reactive

我想交换一对嵌套IObservables的排序,并对其发生的方式有一些限制。

作为一个具体的(虽然有点做作)的例子,假设有一个游戏服务器托管连续的在线多人游戏。玩家可以随时加入并在每个游戏中执行操作。以下类具有工作实现,其提供玩家在连续游戏期间执行的动作的只读视图:

class GameServer
{
  public IObservable<Game> Games { get { ... } }
}

class Game
{
  public int GameId { get { ... } }
  public IObservable<GamePlayer> Players { get { ... } }
}

class GamePlayer
{
  public int PlayerId { get { ... } }
  public IObservable<PlayerAction> PlayerActions { get { ... } }
}

在这些类中,有一个嵌套的可观察IObservable<IObservable<IObservable<PlayerAction>>>。这提供了以下表单的信息:There are a series of games. Within each game a series of players joined. Each player performed a number of actions in the game

我想要做的是重新排列这些数据,以便它提供以下信息:There are a number of players. Since each player joined, a series of games have been played. Within each game, the player performed a number of actions.这看起来像是以下方法的实现:

IObservable<Player> Players { get; }

使用以下类:

class Player
{
  public Player(int playerId, IObservable<PlayerGame> games)
  {
    PlayerId = playerId;
    Games = games;
  }

  public int PlayerId { get; private set; }
  public IObservable<PlayerGame> Games { get; private set; }
}

class PlayerGame
{
  public PlayerGame(int gameId, IObservable<PlayerAction> gameActions)
  {
    GameId = gameId;
    GameActions = gameActions;
  }

  public int GameId { get; private set; }
  public IObservable<PlayerAction> GameActions { get; private set; }
}

不是提供一系列游戏并为每个玩家展示每个玩家所做的事情,而是提供一系列玩家并展示他们参与连续游戏的每一个。

还有一个额外的要求:一旦玩家加入,他们对每个连续游戏的动作都应该显示出来,无论他们是否在游戏过程中做了什么(比如玩家在游戏过程中什么都不做) ,Player在游戏开始时仍应推送新的PlayerGame,即使其GameActions从未推送过值。

如何使用Players作为相关数据的来源实施GameServer.Games

(回应DaveSexton的评论:ID代表什么,数据来自何处以及程序使用的框架或环境并不重要。所有必需的数据都出现在{{1}中},GameServerGame类。我只是不知道如何将其重组为GamePlayer形式。)

几乎可行的解决方案

为了更好地了解我的目标,这里有一个几乎可行的解决方案。唯一的问题是,如果新游戏开始并且Player推送新的GameServer.Games,则Game不会相应地为每个现有玩家推送新的Player.Games(我想要它。)

PlayerGame

1 个答案:

答案 0 :(得分:3)

根据OP提供的新信息和示例查询更新了答案

Players  = Games.Publish(publishedGames => 
             from game in publishedGames
             from player in game.Players
             select new Player(
               player.PlayerId, 
               (from game2 in publishedGames
                from player2 in game2.Players
                where player2.PlayerId == player.PlayerId
                select new PlayerGame(game2.GameId, player2.PlayerActions))
                .StartWith(new PlayerGame(game.GameId, player.PlayerActions))))
           .Distinct(player => player.PlayerId)

这实际上只是一个SelectMany查询。对于每个Game,对于每个GamePlayer,它会投影一个新的Player

最初的问题是如何从Player创建新的GamePlayer。您在示例查询中显示的是您只想从PlayerGame对象转换Game个对象;因此,我刚刚使用内部查询来过滤具有玩家ID的游戏。就是这样。

Publish仅用于Games 的情况。如果,那么您不需要Publish

我添加Distinct因为没有它,只要观察到已经观察过的玩家Game,就会再次观察到这些玩家。