【问题标题】:Pass a closure capturing constructor argument to base class constructor将闭包捕获构造函数参数传递给基类构造函数
【发布时间】:2016-04-10 00:18:42
【问题描述】:

我想从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 转换为私有属性),但是我的 F# 习语词汇表中缺少这个。那么,我的第二个问题是,这样做的惯用方式是什么。

【问题讨论】:

  • 我怀疑惯用的方法是使 hash_stream 成为以 hasher 作为参数的顶级绑定
  • @JohnPalmer:有道理,谢谢。

标签: f#


【解决方案1】:

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

如果您想要尽可能接近您问题中的版本,那么您可以在构造函数中移动 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 在 cmets 中的建议,将流的实现移到类之外,可能会更有意义:

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)

【讨论】:

  • 谢谢 Tomas,这两种方法都有意义,也许可以称为惯用方法。您是否知道为什么首先做出这个设计决策(特殊构造函数参数范围的决策)?
猜你喜欢
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2014-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
相关资源
最近更新 更多