本体
static void DumpHex(byte[] data, int width = 16, int offset = 0)
=> Console.WriteLine(string.Join("\n",
data
.Select((a, i) => (i, a))
.GroupBy(a => (a.i + offset) / width, a => a.a)
.Select((a, i) => string.Join(" ",
$"{a.Key * width:X8}",
$"{"".PadLeft(i == 0 ? offset % width * 3 : 0)}{string.Join(' ', a.Select(a => $"{a:X2}"))}".PadRight(width * 3),
$"{"".PadLeft(i == 0 ? offset % width * 1 : 0)}{string.Join("", a.Select(a => ' ' <= a && a <= '~' ? (char)a : '.'))}"))));
使い方
シンプルな16進ダンプ
var a = new byte[40];
new Random(1234).NextBytes(a);
DumpHex(a);
結果
00000000 E5 6C 53 0C C0 BD 3B C9 C4 7E 74 78 9B 11 19 82 .lS...;..~tx....
00000010 2C 1A CE 5B 53 8B 66 65 DB D2 09 DF 80 F2 20 E8 ,..[S.fe...... .
00000020 7E 43 88 8F 97 CB 23 50 ~C....#P
オフセットや幅を与えた場合
var a = new byte[40];
new Random(1234).NextBytes(a);
DumpHex(a, width: 32, offset: 60);
結果
00000020 E5 6C 53 0C .lS.
00000040 C0 BD 3B C9 C4 7E 74 78 9B 11 19 82 2C 1A CE 5B 53 8B 66 65 DB D2 09 DF 80 F2 20 E8 7E 43 88 8F ..;..~tx....,..[S.fe...... .~C..
00000060 97 CB 23 50 ..#P