分享

c# – 颠倒嵌套IObservable的顺序

 印度阿三17 2019-06-28

我想交换一对嵌套IObservable的排序,并对它发生的方式有几个约束.

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

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>>>.这是给出形式的信息:有一系列游戏.在每场比赛中,一系列球员加入.每个玩家在游戏中执行了许多动作.

我想要做的是重新排列这些数据,以便它提供以下信息:有许多玩家.由于每个玩家加入,已经玩了一系列游戏.在每个游戏中,玩家执行了许多动作.这看起来像是以下方法的实现:

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

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

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

我如何使用GameServer.Games作为相关数据的来源实现玩家?

(回应DaveSexton的评论:ID代表什么,数据来自何处以及程序运行的框架或环境并不重要.所有必需的数据都存在于GameServer,Game和GamePlayer类中.我只是不喜欢我不知道怎么把它改组成播放器形式.)

一个几乎可行的解决方案

为了更好地了解我的目标,这里有一个几乎可行的解决方案.唯一的问题是,如果一个新游戏开始并且GameServer.Games推送一个新游戏,则Player.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))));

解决方法:

根据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查询.对于每个游戏,对于每个GamePlayer,它都会投射一个新玩家.

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

发布仅用于游戏很冷的情况.如果它很热,那么你不需要发布.

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

来源:https://www./content-1-278101.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多