C# 中基元类型的容器是否使用值语义或指针/引用语义
本文关键字:语义 指针 引用 是否 类型 | 更新日期: 2023-09-27 18:33:51
当在 C# 中创建基元类型的List<>
(例如 List<int>
)时,列表中的元素是按值存储,还是按引用存储?
换句话说,C# List<int>
等同于C++ std::vector<int>
还是C++ std::vector<shared_ptr<int>>
?
List<int>
内部将有一个int[]
。通常不需要装箱 - 值直接存储在数组中。当然,如果您选择将List<T>
用作非通用IList
,其中 API 是根据 object
定义的,这将框:
List<int> list1 = new List<int>();
// No boxing or unboxing here
list1.Add(5);
int x = list1[0];
// Perfectly valid - but best avoided
IList list2 = new List<int>();
// Boxed by the caller, then unboxed internally in the implementation
list2.Add(5);
// Boxed in the implementation, then unboxed by the caller
int y = (int) list2[0];
请注意,短语"通过引用存储"是一个令人困惑的短语 - 术语"通过引用"通常用于参数传递的上下文中,它有些不同。
因此,虽然List<string>
(例如)包含一个数组,其中每个元素值都是一个引用,但在List<int>
中,每个元素值只是一个int
。唯一涉及的引用是对List<int>
的调用者引用,以及对数组的内部引用。(数组类型本身始终是引用类型,即使元素类型是值类型也是如此。
值类型按值存储。(例如基元和结构)引用类型按引用存储。(例如课程)
那么,如果你编写这样的代码会发生什么:
struct MutableValueType
{
public int ChangableInt32;
}
static class Program
{
static void Main()
{
var li = new List<MutableValueType>();
li.Add(new MutableValueType());
li[0].ChangableInt32 = 42;
}
}
您会修改结构的副本,还是会更改List<>
内的副本?编译器会警告你吗?我想试试这个。