为了接下来的问题,假设我想将纯文本字符串转换为十六进制字符串;例如,“你好,世界!”进入“48656c6c6f2c20576f726c6421”。
这需要两个步骤:
例如:
string plainText = "Hello, World!";
byte[] bytes = Encoding.Default.GetBytes(plainText);
string hexadecimalString = Convert.ToHexString(bytes);
接下来,我想将此功能包装到实用函数中。在 .NET Core 2.1 之前(我很惊讶
ReadOnlySpan<T>
这么老),最灵活的方法是重载 string
和 char[]
;例如:
public static string ToHexString(string value, Encoding? encoding = null) =>
ToHexString(value.ToCharArray(), encoding);
public static string ToHexString(char[] value, Encoding? encoding = null) =>
Convert.ToHexString((encoding ?? Encoding.Default).GetBytes(value));
虽然这种方法相对简单,但从分配的角度来看,它并不是特别好,因为需要三个分配:
ToCharArray()
将分配一个新的 char[]
。GetBytes
将分配一个新的 byte[]
ToHexString
将分配一个新的 string
。引入
ReadOnlySpan<T>
有可能通过减少分配数量(尽管只减少 1)来改善这一点,而且从可维护性的角度来看,它需要更少的方法重载,因为 string
和 char[]
可以隐式转换为ReadOnlySpan<char>
;例如(在理想世界中):
public static string ToHexString(ReadOnlySpan<char> value, Encoding? encoding = null) =>
Convert.ToHexString((encoding ?? Encoding.Default).GetBytes(value));
讽刺的是,虽然
ReadOnlySpan<T>
理论上应该减少分配数量,但这里的问题是GetBytes
没有需要ReadOnlySpan<char>
的过载,因此,实现这一点的唯一方法是重新引入分配;例如:
public static string ToHexString(ReadOnlySpan<char> value, Encoding? encoding = null) =>
Convert.ToHexString((encoding ?? Encoding.Default).GetBytes(value.ToArray()));
目前,减少分配的唯一方法是提供方法重载,并单独实现它们;例如:
public static string ToHexString(string value, Encoding? encoding = null) =>
Convert.ToHexString((encoding ?? Encoding.Default).GetBytes(value));
public static string ToHexString(char[] value, Encoding? encoding = null) =>
Convert.ToHexString((encoding ?? Encoding.Default).GetBytes(value));
现在我们有一些方法可以减少分配,因为没有从
string
到 char[]
或 ReadOnlySpan<char>
到 char[]
的转换,但权衡是这会导致更高的可维护性成本,正如我现在所拥有的维护两个方法,以及为调用者提供不太灵活的 API。
所以,我的问题是,什么时候使用 ReadOnlySpan<T>
作为方法参数与使用更显式/重载的类型是正确的?权衡应该偏向于可维护性和依赖于隐式类型转换的健壮 API,还是偏向于性能?有这方面的指导吗?
public static string ToHexString(ReadOnlySpan<char> value, Encoding? encoding = null)
{
encoding ??= Encoding.Default;
int count = encoding.GetByteCount(value);
Span<byte> bytes = stackalloc byte[count];
encoding.GetBytes(value, bytes);
return Convert.ToHexString(bytes);
}