f# - 将捕获构造函数参数的闭包传递给基类构造函数

标签 f#

我想从 System.IO.BinaryWriter 派生一个类,并使用自定义 Stream 调用它的构造函数,其实现捕获派生的构造函数参数类型。对于我的生活,我什至无法弄清楚这是否可能。我基本上想做的是,稍微修剪成 MCV,是

type HashingBinaryWriter private
     (hasher   : System.Security.Cryptography.HashAlgorithm,
      stream   : System.IO.Stream) =
   inherit System.IO.BinaryWriter(stream)

   let unsupp() = raise(System.NotSupportedException())
   let hash_stream =
      { new System.IO.Stream() with
         member __.CanRead = false
         member __.CanSeek = false
         member __.CanWrite = true
         member __.Length = unsupp()
         member __.Position with get() = unsupp() and set(_) = unsupp()
         member __.Seek(_,_) = unsupp()
         member __.SetLength _ = unsupp()
         member __.Read(_,_,_) = unsupp()
         member __.Flush() = ()
         member __.Write(buffer, offset, count) =
            hasher.TransformBlock(buffer, offset, count, null, 0) |> ignore
      }

   new(hasher) = new HashingBinaryWriter(hasher, hash_stream)
   // Or, alternatively
   new(hasher) as me = new HashingBinaryWriter(hasher, me.hash_stream)

最后一行编译失败,因为 hash_stream 未定义,无论是哪种形式。显然,作为this answer建议,构造函数参数的范围不同于类声明主体的范围,但我需要了解这里发生了什么(如果可能的话,还有 F# 设计决策背后的原因)。

的确,我可以看到一些解决方法(例如,将 hash_stream 转换为私有(private)属性),但我的 F# 习语词汇表中缺少这个。那么,我的第二个问题是,这样做的惯用方式是什么。

最佳答案

有多种方法可以做到这一点 - 我想正确的选择取决于您的完整实现的外观。

如果你想要尽可能接近你问题中的版本的东西,那么你可以在构造函数中移动 unsupphash_stream :

type HashingBinaryWriter private
     (hasher   : System.Security.Cryptography.HashAlgorithm,
      stream   : System.IO.Stream) =
    inherit System.IO.BinaryWriter(stream)

    new(hasher : System.Security.Cryptography.HashAlgorithm) = 
        let unsupp() = raise(System.NotSupportedException())    
        let hash_stream =
            { new System.IO.Stream() with
                member __.CanRead = false
                member __.CanSeek = false
                member __.CanWrite = true
                member __.Length = unsupp()
                member __.Position with get() = unsupp() and set(_) = unsupp()
                member __.Seek(_,_) = unsupp()
                member __.SetLength _ = unsupp()
                member __.Read(_,_,_) = unsupp()
                member __.Flush() = ()
                member __.Write(buffer, offset, count) =
                  hasher.TransformBlock(buffer, offset, count, null, 0) |> ignore
            }  
        new HashingBinaryWriter(hasher, hash_stream)

我想如果您的 hash_stream 实现变长,这很容易变得丑陋。在这种情况下,按照 John 在评论中的建议将流的实现移到类之外,也许移到辅助模块中会更有意义:

let unsupp() = raise(System.NotSupportedException())

let createHashStream (hasher : System.Security.Cryptography.HashAlgorithm) =
    { new System.IO.Stream() with
        member __.CanRead = false
        member __.CanSeek = false
        member __.CanWrite = true
        member __.Length = unsupp()
        member __.Position with get() = unsupp() and set(_) = unsupp()
        member __.Seek(_,_) = unsupp()
        member __.SetLength _ = unsupp()
        member __.Read(_,_,_) = unsupp()
        member __.Flush() = ()
        member __.Write(buffer, offset, count) =
          hasher.TransformBlock(buffer, offset, count, null, 0) |> ignore
    }  

type HashingBinaryWriter private
     (hasher   : System.Security.Cryptography.HashAlgorithm,
      stream   : System.IO.Stream) =
    inherit System.IO.BinaryWriter(stream)
    new(hasher : System.Security.Cryptography.HashAlgorithm) = 
        new HashingBinaryWriter(hasher, createHashStream hasher)

关于f# - 将捕获构造函数参数的闭包传递给基类构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36524292/

相关文章:

collections - 该算法已经存在高阶函数了吗?

list - 如何创建特定运行时类型的空列表

f# - 使用acceptJson时Saturn API不响应GET

c# - 如何将列表从 C# 传递到 F#?

f# - 避免使用 "mutable"变量来调用带有 byref(C# 中的 out)参数的方法?

F# 计算表达式透明状态通过 Bind 传递

f# - 根据输入 F# 的类型比较类型和过程函数

f# - 寓言实现外部接口(interface)编译错误

f# - 如何将使用 Shell COM 的 C# 代码转换为 F#?

visual-studio - 有没有办法在 Visual Studio 中对 F# 中的阴影值发出警告?