去年,我问过如何遍历和打印锯齿状数组,而不必为要添加的每个维编写重载函数。锯齿状阵列的通用打印。
我再次遇到了问题,并能够像这样解决它。它与我得到的答案之一相似,但不完全相同。
static string Print<T>(T[] array)
{
string str = "[ ";
for (int i = 0; i < array.Length; i++)
{
str += array[i];
if (i < array.Length - 1)
str += ", ";
}
return str + " ]\n";
}
static string Print<T>(T[][] array)
{
string str = "";
for (int i = 0; i < array.Length; i++)
{
var sub = array[i];
if (sub.Length != 0 && sub[0] is Array)
str += PrintDynamic(sub);
else
str += Print(sub);
}
return str + "\n";
}
private static string PrintDynamic(dynamic array)
{
return Print(array);
}
它工作正常,我得到正确的输出:
var twoDim = new int[][]
{
new int[] { 0, 1, 2, 3 },
new int[] { 0, 1, 2 },
new int[] { 0 }
};
var threeDim = new int[][][] { twoDim, twoDim }
Console.WriteLine(Print(threeDim));
// Output:
// [ 0, 1, 2, 3]
// [ 0, 1, 2]
// [ 0 ]
//
// [ 0, 1, 2, 3]
// [ 0, 1, 2]
// [ 0 ]
但是我仍然不满意,因为如果我不需要PrintDynamic()
并且我可以写的话,会更好
str += Print(sub);
代替
str += PrintDynamic(sub);
那就是我的问题的出处。如果更改那一行,则不会出现任何错误,但是输出将变为
// [ System.Int32[], System.Int32[], System.Int32[], System.Int32[]]
// [ System.Int32[], System.Int32[], System.Int32[]]
// [ System.Int32[] ]
//
// [ System.Int32[], System.Int32[], System.Int32[], System.Int32[]]
// [ System.Int32[], System.Int32[], System.Int32[]]
// [ System.Int32[] ]
因为Print<T>(T[] array)
被调用而不是Print<T>(T[][] array)
。Print<T>()
从调用时编译器如何知道使用哪个PrintDynamic(dynamic array)
,而从内部调用时却不知道Print<T>()
?
回答您的原始问题。你打电话时:
str += Print(sub)
并且该方法的原始对象是int[][][]
,则<T>
该方法的是int[]
。所以,你在呼唤Print(sub)
有T[]
,哪里T
是int[]
。
因此,选择as的T[]
重载Print
,并且-一切都按预期进行。这是在编译时解决的,并且是编译器可以最好地利用其所拥有的信息。T
int[]
请记住,一个通用方法只能编译到IL一次-您不会因为碰巧调用它的方式不同而获得“不同版本”(与C ++模板不同)。通用方法的行为必须对所有可能的输入均有效。因此,如果该方法接收T[][]
,并且您在内部提取了子元素,则它只能将子对象类型视为T[]
。它在运行时无法检测到“哦,实际上T是一个int [],所以我将调用另一个重载”。无论输入什么,该方法都只会调用T[]
重载Print(sub)
。
但是,在使用的情况下dynamic
,您将忽略在编译时产生的所有通用类型信息,而是说“在运行时使用反射现在实际上是什么类型”。现在哪种方法最合适?使用那个!此行为的开销很大,因此必须通过使用dynamic
关键字来显式请求。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句