2016-04-10 3 views
3

Я хочу получить класс от 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 # design design).

Действительно, я могу увидеть некоторые обходные пути (например, конвертировать hash_stream в частную собственность), но мой словарь идиом F # этого не хватает. Тогда мой второй вопрос: какой будет идиоматический способ сделать это.

+0

Я подозреваю, идиоматическое способом было бы сделать 'hash_stream' связывает верхний уровень, который принял' hasher' в качестве аргумента –

+0

@JohnPalmer: Имеет смысл, спасибо. – kkm

ответ

4

Существует несколько способов сделать это - и я думаю, что правильный выбор зависит от того, как будет выглядеть ваша полная реализация.

Если вы хотите что-то как можно ближе к версии в вашем вопросе, как это возможно, то вы можете просто двигаться unsupp и hash_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 увеличивается. В этом случае, было бы больше смысла делать то, что Джон предлагает в комментариях и переместить реализацию потока за пределами класса, возможно, во вспомогательный модуль:

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) 
+0

Спасибо Томасу, оба подхода имеют смысл и, возможно, можно назвать идиоматическими. Знаете ли вы, почему * это дизайнерское решение (в частности, область аргументов специального конструктора) было сделано в первую очередь? – kkm

Смежные вопросы