string.Join处理byte数组与startIndex、count时的异常行为疑问
string.Join(", ", byteArr, 0, 5)返回System.Byte[], 0, 5? 这是个很有意思的问题,核心原因是C#编译器的方法重载匹配规则和string.Join的重载设计导致的,我们一步步拆解:
发生了什么?
当你调用string.Join(", ", stringArr, 0, 5)时,编译器匹配到了专门针对字符串数组的重载:Join(string separator, string[] value, int startIndex, int count),所以它能正确截取前5个元素并连接。
但对于byte[],没有专门的非泛型重载,而编译器在匹配时,错误地选择了Join(string separator, params object[] values)这个重载——这个重载会把你传入的byteArr、0、5这三个参数当成独立的对象,分别调用它们的ToString()方法后连接,于是就得到了System.Byte[], 0, 5(byteArr.ToString()默认返回类型名)。
为什么编译器会选这个重载?
你可能会疑惑:string.Join不是有针对数组的Join(string separator, Array value, int startIndex, int count)重载吗?为什么没匹配到?
问题出在值类型数组的重载匹配优先级上:虽然byte[]继承自Array,但在某些.NET环境或编译器版本中,编译器会优先选择参数更“通用”的params object[]重载,而非针对Array的重载。另外,泛型重载Join<T>(string separator, IEnumerable<T> values, int startIndex, int count)虽然可以处理byte[](因为它实现了IEnumerable<byte>),但编译器需要推断类型T,这个推断的优先级低于直接匹配object参数的重载。
怎么解决?
有几种方法可以让编译器匹配到正确的重载:
显式指定泛型参数:
Console.WriteLine(string.Format("0 - 5 byteArr: {0}", string.Join<byte>(", ", byteArr, 0, 5)));这样编译器会直接使用泛型重载,正确遍历
byte[]的元素。强制转换为
IEnumerable<byte>:Console.WriteLine(string.Format("0 - 5 byteArr: {0}", string.Join(", ", (IEnumerable<byte>)byteArr, 0, 5)));明确告诉编译器我们要使用针对枚举的泛型重载。
使用LINQ的
Skip和Take:Console.WriteLine(string.Format("0 - 5 byteArr: {0}", string.Join(", ", byteArr.Skip(0).Take(5))));这种方式更直观,也避开了重载匹配的问题。
验证结果
用上面的方法修改后,0 - 5 byteArr的输出就会和字符串数组一样,得到1, 2, 3, 4, 5。
内容的提问来源于stack exchange,提问作者Andis59

