如何处理在每个方法调用中检查有效状态

How to deal with checking for valid state in every method call

我遇到过类似这样的代码。

member this.Send (data:array<byte>) =
    if tcpClient.Connected then
        // Send something.

member this.Open () =
    if not tcpClient.Connected then
        // Connect.

这是一个潜在的错误配置单元,在对其执行操作之前不断检查 TcpClient 是否已连接。

一个类似的问题是在对某个东西执行操作之前检查它是否 null

处理此问题的一般方法是什么? 我在想一个 monad 的思路,它抽象了这个无聊的检查。

编辑:
可能我可以编写许多方法,每个方法都必须检查我们是否已连接。

member this.SendName name =
    if tcpClient.Connected then
        // Send name

member this.ThrottleConnection percent =
    if tcpClient.Connected then
        // Throttle

member this.SendAsTest text =
    if tcpClient.Connected then
        // Send as text.

因此,这取决于您是要在包装器内部还是外部进行检查 class。在 class 中进行检查,我看不出计算表达式是如何真正相关的;你没有绑定操作。

工作流表达式只有在您在包装器外部进行检查时才有用 class(即从调用函数)。如果您一起创建一个 connected 构建器,生成的代码将类似于

connected {
  do! wrapper.Send(..)
  do! wrapper.Throttle(..)
  do! wrapper.SendAsTest(..)
}

不过,那真的不比

简单
if wrapper.connected do
  wrapper.Send(..)
  wrapper.Throttle(..)
  wrapper.SendAsTest(..)

那么,有什么意义,对吧?

如果您有多个 tcpClient 包装器对象并且需要将它们全部连接到您的工作流中,这会更有意义。这就是 "monadic" 方法的用途。

connected {
  do! wrapper1.Send(..)
  do! wrapper2.Throttle(..)
  do! wrapper3.SendAsText(..)
}

但是,具体到您在包装器内部进行检查的示例 class,正如我之前所说,monad 将不适用。解决该特定问题的一种巧妙方法是尝试模仿一些先决条件,例如以下 link http://laurent.le-brun.eu/site/index.php/2008/03/26/32-design-by-contract-with-fsharp。我不知道它是否比 if 语句更直观,但如果您正在寻找一种有趣的 fsharp-y 方式来做事,那是我能想到的最好的方法。

最终,您现有的代码将尽可能紧凑。大概不是 所有 的函数都以相同的 if 语句开头,所以那里没有不必要的重复。