Structs是否总是堆栈分配或有时堆分配?

Car*_*ngo 38 c# struct allocation

我的印象是在C#中,struct元素在堆栈上分配,因此从创建它们的方法返回时会消失.但是如果我将struct-values放在一个列表中并返回它会发生什么?元素幸存下来.是否有时在堆上分配struct实例?

internal struct Stru
{
  public int i;
}

internal class StruTry
{
  public List<Stru> Get(int max)
  {
    var l = new List<Stru>();
    for (int i = 0; i < max; i++)
      l.Add(new Stru {i=i});

    return l;
  }
}
Run Code Online (Sandbox Code Playgroud)

代码打印0,1,2

[Test]
public void T()
{
  var ll = new StruTry().Get(3);
  foreach (var stru in ll)
    Console.WriteLine("* "+ stru.i);
}
Run Code Online (Sandbox Code Playgroud)

jas*_*son 56

首先,阅读Eric Lippert在The Stack这篇文章是一个实现细节.遵循关于价值类型的真相.至于你的具体问题

是否有时在堆上分配struct实例?

是的,它们有时被分配在堆上.有很多例子可以在堆上分配它们.如果它们是盒装的,或者它们是类中的字段,或者它们是数组的元素,或者它们是已被关闭的值类型变量的值,等等.

但是如果我将struct-values放在一个列表中并返回它会发生什么?元素幸存下来.

您正在考虑这种方式,这是可能分配值类型的重点之一.有关更多详细信息,请参阅我在"关于值类型的真相"中提到的第二篇文章.但请记住,堆栈是一个实现细节.关键的一点是,你真的不需要关心这些东西.您应该关注值类型和引用类型之间的语义差异.

  • 最后一点只关注"我是通过值还是通过引用传递"而不是"我是堆栈或堆栈中的对象" - 对我来说很难,因为我主要用C++编程.我认为任何C/C++程序员都会根据对象的位置来思考.在C/C++中,结构体(以及C++中的类)可以根据它们的声明方式存在于任何一个地方.似乎任何C/C++程序员在C#中工作的主要任务就是打破这种习惯,从不考虑对象的位置. (4认同)

Mar*_*tos 18

结构就像整数.如果你有一个本地int,它通常会在堆栈上,如果你有一个int列表,它们会直接存储在列表的内部数组中.结构的行为方式相同.


Tri*_*ped 5

但是如果我将struct-values放在一个列表中并返回它会发生什么?元素幸存下来.

从技术上讲,添加到"列表"的值不是相同的值,它们是基于值的副本.例如,如果您修改原件,则不会将这些更改传送到列表中的副本.此外,'List'返回指定索引处的值的副本.这意味着如果结构是可变的并且您修改了从"List"返回的值,那么该值中的值List<t>将保持不变.这不是数组的情况,因为数组索引提供对实际变量的访问.