我想交换一对嵌套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}中},GameServer
和Game
类。我只是不知道如何将其重组为GamePlayer
形式。)
为了更好地了解我的目标,这里有一个几乎可行的解决方案。唯一的问题是,如果新游戏开始并且Player
推送新的GameServer.Games
,则Game
不会相应地为每个现有玩家推送新的Player.Games
(我想要它。)
PlayerGame
答案 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
,就会再次观察到这些玩家。