Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该如何在FRP(Rx.Net)中建模循环依赖关系?_C#_System.reactive_Reactive Programming_Circular Dependency_Rx.net - Fatal编程技术网

C# 我应该如何在FRP(Rx.Net)中建模循环依赖关系?

C# 我应该如何在FRP(Rx.Net)中建模循环依赖关系?,c#,system.reactive,reactive-programming,circular-dependency,rx.net,C#,System.reactive,Reactive Programming,Circular Dependency,Rx.net,我试图通过使用Rx.Net实现Tic-Tac-Toe来学习更多关于函数式反应式编程的知识。我面临的问题是,在我的游戏逻辑中似乎存在循环依赖 命令流(PlaceToken,ResetGame等)是从用户输入流生成的 游戏的当前状态(boardStates)是通过将命令应用于前一个状态,从初始状态开始计算得出的: var initialBoardState = new BoardState(); var boardStates = commands .Scan(initialBoardSt

我试图通过使用Rx.Net实现Tic-Tac-Toe来学习更多关于函数式反应式编程的知识。我面临的问题是,在我的游戏逻辑中似乎存在循环依赖

命令流(
PlaceToken
ResetGame
等)是从用户输入流生成的

游戏的当前状态(
boardStates
)是通过将
命令
应用于前一个状态,从初始状态开始计算得出的:

var initialBoardState = new BoardState();

var boardStates = commands
    .Scan(initialBoardState, (boardState, command) => command.Apply(boardState))
    .DistinctUntilChanged();
但是,
命令
流应取决于
boardStates
流。这是因为有效的命令集随当前状态而变化

例如,
PlaceToken
命令只应在用户单击空磁贴时发出,但空磁贴集由当前状态定义


总之,我有两条流,它们似乎相互依赖。在函数式反应式编程中,我应该如何解决这一问题?

并非所有事情都需要成为事件。记住,Rx/回调是一种允许您依赖的东西给您回电话(而不依赖您)的方式

作为经验法则

  • 循环依赖关系表示存在设计缺陷
  • 发送命令,接收事件
  • 2) 也可以翻译成

    只需调用依赖项上的方法来更改它们的状态,但订阅它们的事件来查看它们的更改

    因此,不要将命令视为一个流,而应该将用户操作视为一个流,当听到该流时,可能会创建一个命令

    所以董事会成员可能看起来像这样

    public class BoardState
    {
        public void PlaceToken(PlaceTokenCommand placeToken)
        {
            //Process, then raise event
        }
    
        public void Reset()
        {
            //Process, then raise event
        }
    
        public IObservable<?> StateUpdates()
        {
    
        }
    }
    
    public class TicTacToeViewModel
    {
        private readonly BoardState _board;
        public TicTacToeViewModel()
        {
            _board = new BoardState();
            MoveTokenCommand = new DelegateCommand(MoveToken, CanMoveToken);
            ResetBoardCommand = new DelegateCommand(_board.Reset);
    
            board.StateUpdates(state => UpdatePresentation(state));
        }
    
        public DelegateCommand MoveTokenCommand { get; private set;}
        public DelegateCommand ResetBoardCommand { get; private set;}
    
    
        private void MoveToken()
        {
            var token = CurrentToken;
            var location = ActiveLocation;
            var cmd = new PlaceTokenCommand(token, location);
            _board.PlaceToken(cmd);
        }
    
        private bool CanMoveToken()
        {
            //?
        }
    }
    
    但是作为@Enigmativity,评论中的请求,如果没有MCVE,很难提供合理的帮助


    最后一点注意,虽然Rx是功能性的,而且是反应性的,但狂热者会反对将Rx视为FRP(参见Conal,行为等)。

    虽然@LeeCampbell的解决方案确实有效,但它需要使您的核心模型类可变。相反,我发现最好复制cycle.js采用的方法。你可以看到他们的解释

    问题是我们有一个循环。行动流取决于董事会状态流,而董事会状态流又取决于行动流:

    boardStream = f(actionStream)
    actionStream = g(boardStream)
    
    cycle.js解决方案是使用代理流将所有内容连接在一起:

    // Create a proxy
    proxyActionStream = new Stream()
    
    // Create our mutually dependent streams using the proxy
    boardStream = f(proxyActionStream)
    actionStream = g(boardStream)
    
    // Feed actionStream back into proxyActionStream
    actionStream.Subscribe(x => proxyActionStream.OnNext(x))
    
    在Rx.NETLand中,代理流应该是
    ReplaySubject

    你唯一需要注意的地方就是失控的反馈循环:如果你的流从未稳定下来,那么它们就会撞上一个无限循环!将流视为相互递归是很有帮助的

    你真的需要一份工作来做这件事。