Si las estructuras están hechas de tipos simples, entonces puede hacer una matriz de punteros. Sí, los punteros en C# son muy útiles para casos como el suyo. Sin embargo, hay limitaciones. Las estructuras originales deben almacenarse en un Array
y no en un List<>
. Mire el siguiente ejemplo compilado con unsafe
indicador de compilación.
[StructLayout(LayoutKind.Sequential)]
public struct Vec3
{
public double X, Y, Z;
public double Mag { get { return Math.Sqrt(X * X + Y * Y + Z * Z); } }
}
public unsafe class Vec3ArrayProxy
{
Vec3*[] ptr = null; //internal array of pointers
public Vec3ArrayProxy(Vec3[] array)
{
ptr = new Vec3*[array.Length]; //allocate array
fixed (Vec3* src = array) //src holds pointer from source array
{
for (int i = 0; i < array.Length; i++)
{
ptr[i] = &src[i]; //take address of i-th element
}
}
}
public Vec3ArrayProxy(Vec3ArrayProxy other)
{
//just use all the existing pointers
ptr = (Vec3*[])other.ptr.Clone();
//or I could say:
//ptr = other.ptr;
}
// Access values with index
public Vec3 this[int index]
{
get { return *ptr[index]; }
set { *ptr[index] = value; }
}
public int Count { get { return ptr.Length; } }
// Access the array of pointers
public Vec3*[] PtrArray { get { return ptr; } }
// Copy the values of original array into new array
public Vec3[] ToArrayCopy()
{
Vec3[] res = new Vec3[ptr.Length];
for (int i = 0; i < res.Length; i++)
{
res[i] = *ptr[i];
}
return res;
}
}
unsafe class Program
{
static void Main(string[] args)
{
const int N = 10; //size of array
// Allocate array in memory
Vec3[] array = new Vec3[N];
// Assign values into array
for (int i = 0; i < N; i++)
{
array[i] = new Vec3() { X = i, Y = 0, Z = 0 };
}
//Build proxy to array (with pointers)
Vec3Array A = new Vec3Array(array);
// Reference the same pointers as A
Vec3Array B = new Vec3Array(A);
// Change the original array
array[4].X = -4;
// Or change via a copy
A.PtrArray[5]->Y = -5;
// Or assign a new value
B[0] = B[9];
// Show contents of array via proxy A
Console.WriteLine("{0,-6}|{1,6}|{2,6}|{3,6}|{4,6}",
"i", "X", "Y", "Z", "Mag");
for (int i = 0; i < N; i++)
{
Console.WriteLine("{0,6}|{1,6:F2}|{2,6:F2}|{3,6:F2}|{4,6:F3}",
i + 1, A[i].X, A[i].Y, A[i].Z, A[i].Mag);
}
}
}
Disculpa el código largo, pero quería mostrar todas las características de struct pointers.La razón por la que List<>
no funcionará es porque no puede tomar un puntero a un elemento de lista. Si realmente realmente realmente debe utilizar un List<>
, a continuación, extraer el conjunto del ámbito privado _items
con el siguiente código:
static T[] ExtractArray(List<T> list)
{
//list.TrimExcess();
var t = list.GetType();
var items = t.GetField("_items",
BindingFlags.NonPublic | BindingFlags.Instance);
return items.GetValue(list) as T[];
}
crudo que sea, funciona y una vez que haya hecho la reflexión sobre List<>
una vez, puede almacenar en caché los resultados en un campo estático y solo llama al items.GetValue(list)
cada vez.
Crea una clase que almacene la estructura. Tenga mucho cuidado con la optimización prematura, las matrices de punteros tienen una localidad de memoria caótica pésima. –
¿Cuánto más grande que una referencia es la estructura? Se supone que las estructuras son pequeñas; si son mucho más grandes que una referencia de que el tiempo de copiado es su cuello de botella, es posible que no desee utilizar una estructura en primer lugar. ¿Puedes dar más detalles? –
Bueno, la referencia solo toma 4 bytes, por lo que cualquier elemento más grande que un flotante o entero ya es más grande que eso. Si haces los cálculos, incluso si soy muy modesto y solo almacena un Vector4 simple, la relación ya es 4: 1, y esto no es nada cerca de una estructura grande. – Adi