只是使输出数组不可变
你可以考虑这样的事情:
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);
}
}
这不会使数组不可变,但私有不是问题。
一个可能更好的解决方案:封装 Huffman Stream 对象
您还可以选择实现自己的HuffmanStream
,它会为您处理标题的细节和其他方面!我实际上认为这是理想的,因为它将 Huffman 流的所有关注点封装到一段可测试的代码中,而不是在你需要使用的每个地方都重复。
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()
。MyHuffmanStream
不需要这个,因为它使用MemoryStream
,这是可以信任的。