2016-04-10 8 views
3

Ich möchte eine Klasse von System.IO.BinaryWriter ableiten und ihren Konstruktor mit einer benutzerdefinierten Stream aufrufen, deren Implementierung ein Konstruktorargument des abgeleiteten Typs erfasst. Für das Leben von mir kann ich nicht herausfinden, ob das überhaupt möglich ist. Was ich im Wesentlichen zu tun versuchen, getrimmt zu leicht ein MCV zu sein, istÜbergeben Sie ein Closing-Capturing-Konstruktorargument an den Basisklassenkonstruktor

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) 

Die letzte Zeile nicht in jeder Form zu kompilieren, weil hash_stream nicht definiert ist. Offenbar, wie this answer vorschlägt, unterscheidet sich der Umfang der Konstruktorargumente von dem des Klassendeklarationshauptteils, aber ich muss verstehen, was hier vor sich geht (und wenn möglich das Warum hinter der F # -Entwurfsentscheidung).

In der Tat kann ich einige Problemumgehungen sehen (konvertieren Sie Hash_stream in eine private Eigenschaft, zum Beispiel), aber mein Vokabular von F # idioms fehlt dieser. Meine zweite Frage ist also, was wäre die idiomatische Art, dies zu tun.

+0

vermute ich, der idiomatische Weg zu machen wäre, 'hash_stream' eine Bindung der obersten Ebene, die' hashher' als Argument verwendet –

+0

@JohnPalmer: Macht Sinn, danke. – kkm

Antwort

4

Es gibt mehrere Möglichkeiten, dies zu tun - und ich denke, die richtige Wahl hängt davon ab, wie Ihre vollständige Implementierung aussehen wird.

Wenn Sie etwas wollen, das so nah an der Version in Frage wie möglich ist, dann können Sie nur unsupp und hash_stream innerhalb des Konstruktors bewegen:

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) 

Ich denke, dass dies einfach hässlich, wenn Ihr Implementierung von hash_stream wird länger. In diesem Fall würde es mehr Sinn machen, zu tun, was John in den Kommentaren schlägt vor, und die Umsetzung des Stroms außerhalb der Klasse bewegen, vielleicht in einen Helfer-Modul:

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

Danke Tomas, beide Ansätze machen Sinn und können vielleicht idiomatisch genannt werden. Wissen Sie vielleicht, warum diese Designentscheidung (die des Arguments für den Konstruktorargument) überhaupt getroffen wurde? – kkm

Verwandte Themen