バイト配列を出力にトレースするためにしばらく使用していた古いヘルパー メソッドを見ています。私はずっと前にそれを書きましたが、うまく機能していますが、それを行うためのより良い方法があるかどうか疑問に思っていました (より少ないコードで)。Linq が思い浮かびましたが、私が持っている解決策は非常に非効率的です。私が必要とするのは、「foreach16」の行に沿ったもの、または一度に1つの要素を返す代わりに、列挙可能な要素のグループを返す列挙子です。私自身の列挙子クラスを作成する以外に、それを行う組み込みの方法はありますか?
以下の例には、私が達成しようとしていることに関する詳細情報があります。
元のコード
static void PrintBytes(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
if (i > 0 && ((i % 16) == 0))
{
// end of line, flushes bytes and resets buffer
Console.WriteLine(" {0}", sb.ToString());
sb.Length = 0;
}
else if (i > 0 && ((i % 8) == 0))
{
Console.Write(" ");
sb.Append(' ');
}
Console.Write(" {0:X2}", (int)bytes[i]);
if (' ' <= bytes[i] && bytes[i] <= '~')
{
sb.Append((char)bytes[i]);
}
else
{
// non-ASCII or control chars are printed as '.'
sb.Append('.');
}
}
// flushes the last few bytes
if ((bytes.Length % 16) > 0)
{
// prints spaces where the missing bytes would be
int spacesToPrint = 3 * (16 - (bytes.Length % 16));
if ((bytes.Length % 16) <= 8)
{
spacesToPrint++;
}
Console.Write(new string(' ', spacesToPrint));
}
Console.WriteLine(" {0}", sb.ToString());
}
私が今持っているもの - これは私がコードを単純化しようとしたものです。しかし、私は多くの Skip/Take を実行しているため、コードの複雑さが線形から二次に増加しています。
static void PrintBytesV2(byte[] bytes)
{
for (int i = 0; i < bytes.Length; i += 16)
{
PrintLineV2(bytes, i, Math.Min(16, bytes.Length - i));
}
}
static void PrintLineV2(byte[] array, int offset, int count)
{
Console.Write(
string.Join(
" ",
array
.Skip(offset)
.Take(count)
.Select((b, i) =>
((i == 8) ? " " : "") +
string.Format("{0:X2}", (int)b))));
Console.Write(
new string(
' ',
(16 - count) * 3 +
(count <= 8 ? 1 : 0)) +
" ");
Console.WriteLine(
string.Join(
"",
array
.Skip(offset)
.Take(count)
.Select(b => (' ' <= b && b <= '~') ? (char)b : '.')));
}
新しいコードがそのまま線形であったとしても、1) 動作するので元のコードに固執する可能性が高いことに注意してください。2) より読みやすいと思います。しかし、グループを反復処理する方法があるかどうか疑問に思わずにはいられません。