出力配列を不変にするだけ
次のように考えることができます。
public static class HuffmanConsts {
// output format: Header, serialized tree (prefix), DataDelimiter,
// coded data (logical blocks are 8 byte large, Little Endian)
public const string Extension = ".huff";
private static readonly IReadOnlyList<byte> _header =
// string {hu|m}ff
Array.AsReadOnly(new byte[] {0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66});
private static readonly IReadOnlyList<byte> _dataDelimiter =
// eight binary zeroes, regardless of endianness
Array.AsReadOnly(BitConverter.GetBytes(0L));
public static byte[] Header { get { return _header.ToArray(); } }
public static byte[] DataDelimiter { get { return _dataDelimiter.ToArray(); } }
}
ToArray のパフォーマンスへの影響への対処
ToArray()
ただし、これらのプロパティにアクセスするたびにのオーバーヘッドが発生します。その潜在的なパフォーマンスの低下を軽減するために (注: テストは、実際に存在するかどうかを確認するためのものです!)、以下を使用できますSystem.Buffer.BlockCopy
。
private static readonly byte[] _header =
// string {hu|m}ff
new byte[] {0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66};
private static int BYTE_SIZE = 1;
private static byte[] GetHeaderClone() {
byte[] clone = new byte[_header.Length];
Buffer.BlockCopy(_header, 0, clone, 0, _header.Length * BYTE_SIZE);
return clone;
}
より良い解決策: ストリームへの書き込みをカプセル化する
また、コンシューマがこれらのストリーム コンポーネント自体の詳細をいじる必要がないようにする拡張メソッドを作成することもできます。たとえば、WriteHeader
メソッドは次のようになります。
public static class StreamExtensions {
// include BlockCopy code from above
public static void WriteHuffmanHeader(this Stream stream) {
var header = GetHeaderClone();
stream.Write(header, 0, header.Length);
}
}
これにより配列が不変になることはありませんが、プライベートであることは問題ではありません。
おそらくさらに良い解決策: ハフマン ストリーム オブジェクトをカプセル化する
HuffmanStream
ヘッダーの詳細やその他の側面を処理する独自のものを実装するオプションもあります! ハフマンストリームのすべての問題を、作業する必要があるすべての場所で複製されないテスト可能なコードにカプセル化するので、これは実際には理想的だと思います。
public class HuffmanStream : Stream {
private Stream _stream = new MemoryStream();
private static byte[] _header = ... ;
public HuffmanStream( ... ) {
...
_stream.Write(_header, 0, _header.Length)
// the stream already has the header written at instantiation time
}
}
注:byte[]
インスタンスをに渡す場合Stream.Write()
、メソッドが配列に直接アクセスするため、メソッドが返された後に変更される場合があります。正常に動作Stream
する実装ではそれは行われませんが、カスタム ストリームに対して安全を確保するために、インスタンスを敵対的なものとして扱うStream
必要があります。したがって、インスタンスに、変更してはならない配列への参照を渡してはなりません。たとえば、_header
バイト配列をに渡したいときはいつでも、代わりpossiblyHostileStream.Write()
に渡す必要があります。_header.Clone()
信頼できる をHuffmanStream
使用しているため、これは必要ありません。MemoryStream