如何解决List<T> 的每个元素都装箱了吗?
装箱的 T
只能拆箱为 T
。例如,这不起作用:
object o1 = 5;
double n3 = (double)o1;
在 Cast()
上使用 Linq 的 List<T>
方法会引发类似的异常:
List<int> _numbers = new List<int>() { 1,2,3,4 };
// this is also not working
IEnumerable<double> nums = _numbers.Cast<double>();
- 这是否意味着
List<T>
的每个元素都被装箱? - 是否可以在不创建列表副本的情况下强制转换
List<>
的每个元素?
(请不要使用 Linq 的Select()
方法发布任何答案,因为它正在创建集合的副本)
解决方法
我们在这里只讨论值类型。引用类型遵循不同的规则。
- 这是否意味着
List<T>
的每个元素都被装箱?
没有。 Java 会这样做,在运行时擦除所有类型 T
,并将所有类型重定向到单个 List<Object>
实现(称为 type erasure)。在 .NET 中,对于值类型,每个 List<ValueType1>
、List<ValueType2>
、List<ValueType3>
在运行时都会收到一个不同的实现(请参阅 here)。
- 是否可以在不创建列表副本的情况下强制转换
List<>
的每个元素?
当您将值类型转换为其他内容时,您正在制作它的副本。经常在堆栈上,但副本存在。您不能简单地将值类型作为不同的值类型进行访问。
public static void M1(long n) {
M2((int)n);
}
public static void M2(int n) {
}
在 IL asm 中被翻译为
IL_0000: ldarg.0
IL_0001: conv.i4
IL_0002: call void C::M2(int32)
IL_0007: ret
哪里conv.i4
:
如果转换成功,则将结果值压入堆栈。
请注意,即使 取出 List<int>
的元素也会导致复制:您不会访问 List<int>
内部的元素:
public void M1(List<int> a) {
int v = a[0];
v = 6; // this won't modify a[0]
}
使用数组(以及更新的 C#),您可以直接访问数组的元素:
public void M1(int[] a) {
ref int r = ref a[0];
r = 6; // this will modify a[0]
}
这里的区别在于 List<T>
的索引器(创建 var foo = list[5]
时调用的东西是一个方法,而数组的索引器是一个IL 指令(数组定义在 .NET 虚拟机的最底层,并且有特殊的 OP 来处理它们,List<T>
是构建在数组的“顶部”)。即使在 {{ 上也可以很容易地看到这一点3}}。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。