【问题标题】:Reversing the order of nested IObservables反转嵌套 IObservable 的顺序
【发布时间】:2014-12-24 18:20:55
【问题描述】:

我想交换一对嵌套的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 { ... } }
}

在这些类中,有一个嵌套的 observable IObservable&lt;IObservable&lt;IObservable&lt;PlayerAction&gt;&gt;&gt;。这是给形式的信息: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 从未推送过值。

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

(回应 DaveSexton 的 cmets:ID 代表什么,数据来自哪里以及程序工作的框架或环境并不重要。所有需要的数据都存在于GameServer 中, GameGamePlayer 类。我只是不知道如何将其改组为 Player 表单。)

一个几乎可行的解决方案

为了更好地了解我的目标,这是一个几乎可行的解决方案。唯一的问题是,如果一个新游戏开始并且GameServer.Games 推送一个新的GamePlayer.Games 不会相应地为每个现有玩家推送一个新的PlayerGame(我希望这样做)。

Players = gameServer.Games
  .Select(g => g.Players.Select(p => new { g.GameId, p.PlayerId, p.PlayerActions }))
  .Switch()
  .GroupBy(t => t.PlayerId)
  .Select(
    group => 
    new Player(group.Key, group.Select(t => new PlayerGame(t.GameId, t.PlayerActions))));

【问题讨论】:

  • 您的具体问题是什么?
  • @DaveSexton 在最后添加了一个实际问题——我将如何使用GameServer.Games 作为数据源来实现Players
  • 它不能基于提供的类型来完成(而且我不愿意假设你已经省略的类型)。 GamesGame的序列,其中包含GamePlayer的序列,而PlayersPlayer的序列,其中包含PlayerGame的序列。 GamePlayerPlayerGame 是完全不同的类型。
  • 我想我明白你的意思了 - PlayerPlayerGame 只是围绕它们的属性的简单包装类。如果我将第二组类更改为接口,也许它会使我的要求更清楚。
  • 根据提供的信息,答案是否定的。与Game 类型及其相关类型相比,提议的Player 类型及其相关类型是完全不同的类型。您还没有描述任何在它们之间进行转换的方法。如何从GamePlayer 的列表中获取Player 的列表?后者仅提供PlayerId 属性,而不是Player 类型的属性。

标签: c# system.reactive


【解决方案1】:

更新的答案基于 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

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

Publish 仅在Games的情况下使用。如果它是热门,那么你不需要Publish

我添加了Distinct,因为如果没有它,每当Game 与已观察到的玩家一起被观察到时,这些玩家就会再次被观察到。

【讨论】:

  • 这是导致主要问题的IPlayerGame.GameActions - ID 用于阐明数据移动到的位置。在第一组类中,PlayerActions 是父级Game 中的GamePlayer 采取的操作。在第二组中,GameActions 需要是父 PlayerPlayerGame 中执行的操作(即使 Player 不执行任何操作 - 在这种情况下它应该是一个空序列)。
  • 没有人可以回答您应该如何使用您提供的类型来实现CreatePlayer。这似乎是你的问题,或者至少这是一个先决条件。我对您的应用程序运行的环境一无所知,PlayerId 是指数据库还是演员等。坦率地说,这没关系。即使您提供了这些信息,您的问题也太宽泛了。
  • 对不起,你是对的,我应该提到有问题的 observables 都是热的。
  • 这可能是您在不了解更多可观察来源和环境的情况下所能获得的最佳结果。
  • 嘿 Dave 很高兴再次找到你,几年前你在 Reactive Extensions 上给了我极好的帮助,谢谢!
猜你喜欢
  • 2013-10-27
  • 1970-01-01
  • 1970-01-01
  • 2015-04-05
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 2021-06-12
  • 2012-11-08
相关资源
最近更新 更多