如何在C#中创建包含数组但不使用heap的结构?

如何在C#中创建包含数组但不使用heap的结构?,c#,memory,struct,heap,C#,Memory,Struct,Heap,我需要的是: 具有任意数量顶点(或至少达到max顶点数)的多边形 它应该是一个结构,这样它可以很快,并且可以通过值进行赋值/传递 似乎我不能使用数组或集合来存储顶点,因为这样我的多边形结构将指向堆上的对象,当一个多边形按值指定给另一个多边形时,将只执行浅复制,并且我将使两个多边形都指向同一个顶点数组。例如: Polygon a = new Polygon(); Polygon b = a; // both polygons would be changed b.vertices[0]

我需要的是:

  • 具有任意数量顶点(或至少达到
    max
    顶点数)的多边形
  • 它应该是一个结构,这样它可以很快,并且可以通过值进行赋值/传递
似乎我不能使用数组或集合来存储顶点,因为这样我的多边形结构将指向堆上的对象,当一个多边形按值指定给另一个多边形时,将只执行浅复制,并且我将使两个多边形都指向同一个顶点数组。例如:

Polygon a = new Polygon(); 
Polygon b = a; 
// both polygons would be changed 
b.vertices[0] = 5; 
那么,我如何创建一个可以有任意数量(或固定数量)顶点的结构,但根本不使用heap


我可以使用很多变量,比如
v1、v2、v3。。。v10
等,但我希望或多或少保持代码干净。

如果符合您的逻辑,您可以使用堆栈上分配的
Span
。阅读更多

使用复制构造函数复制数组的另一种方法

public Polygon(Polygon other)
{
    this.vertices = other.vertices.Clone() as int[];
}
然后


您可以选择使用
fixed
关键字定义数组,从而将其放入堆栈中

但是您不能直接访问数组的元素,除非您处于
不安全的
上下文中并使用指针

要获得以下行为:

    static void Main(string[] args)
    {
        FixedArray vertices = new FixedArray(10);
        vertices[0] = 4;

        FixedArray copy = vertices;
        copy[0]  = 8;
        Debug.WriteLine(vertices[0]);
        // 4
        Debug.WriteLine(copy[0]);
        // 8
    }
然后使用以下类定义:

public unsafe struct FixedArray 
{
    public const int MaxSize = 100;

    readonly int size;
    fixed double data[MaxSize];

    public FixedArray(int size) : this(new double[size])
    { }

    public FixedArray(double[] values)
    {
        this.size = Math.Min(values.Length, MaxSize);
        for (int i = 0; i < size; i++)
        {
            data[i] = values[i];
        }
    }

    public double this[int index]
    {
        get
        {
            if (index>=0 && index<size)
            {
                return data[index];
            }
            return 0;
        }
        set
        {
            if (index>=0 && index<size)
            {
                data[index] = value;
            }
        }
    }

    public double[] ToArray()
    {
        var array = new double[size];
        for (int i = 0; i < size; i++)
        {
            array[i] = data[i];
        }
        return array;
    }        
}
  • 堆栈数组字段

     struct StdArray
     {
         int[] vertices;
    
         Foo(int size)
         {
             vertices = new int[size];
         }
     }
    
     unsafe struct FixedArray
     {
         fixed int vertices[100];
         int size;
         Foo(int size)
         {
             this.size = size;
             // no initialization needed for `vertices`
         }
     }
    

  • 您真正关心的是
    堆栈与堆
    还是
    引用类型与值类型
    ?如果是前者,请检查。将一个潜在的大多边形完全放在堆栈内存中并将其传递(每次将其作为函数参数传递时复制它等)并不一定比使用标准集合更快(甚至可能更慢)。您是否有需要修复的实际问题,或者您是否正在尝试先发制人地优化一个可能根本不存在的问题?我觉得在这种情况下,您的问题更多地是关于深度复制列表,而不是关于堆栈与堆。堆栈和堆是实现细节,99%的时候我们都不需要担心。另外,请参见:恕我直言,如果您解释您想要做什么,您可能会得到更好的答案。你的问题是怎么做。请回答你的问题。请记住,C#/Roslyn编译器技术在优化代码和处理数据结构方面做得非常出色。如果您需要比它更聪明,您可能确切地知道它在为您做什么,您应该告诉我们。过早的优化可能会使代码完全无法维护。修复对象不会将其移动到堆栈中,也不会使其表现为值类型。它只是确保GC在其收集过程中不会移动它。@Servy实际上不会,
    fixed
    in structures是一个特殊的关键字,用于移动堆栈中的值。我简化了示例并删除了
    fixed()
    语句,它仍然有效。自那以后,情况有所改善。试试看,你会发现这完全符合要求。据我所知,“fixed”关键字将固定大小的数组作为结构的一部分嵌入。数组位于堆栈还是堆上取决于结构的使用方式。如果它被用作局部变量声明,那么实际上,数据将存在于堆栈上,但是如果它被用作引用类的成员,那么缓冲区将存在于堆上(类的一个实例将整个固定大小的数组作为其字段的一部分嵌入,而不是作为对独立数组的引用)因此,使用
    类Foo{FixedArray data;}
    的声明,数据可能驻留在堆上。这是有道理的,因为结构的要点是将所有数据保存在一起。
     unsafe struct FixedArray
     {
         fixed int vertices[100];
         int size;
         Foo(int size)
         {
             this.size = size;
             // no initialization needed for `vertices`
         }
     }