Adding structure reference to C # lists

Trying to optimize my C # code, I found that if I have a list of structure elements, each insert will be a complete copy - something that I would like to avoid.

In C ++, I would just keep a list of pointers, so I was wondering if I could do the same with C #, possibly having a list as a list of structure references. Unfortunately, a structure cannot be turned into a class, because it is part of the XNA library (Vector3, Matrix, etc.) In any case, what does the format and use look like, if possible?

Thanks.

+6
source share
3 answers

No, basically. Parameters:

  • use a class (you already said you can't)
  • insert it
  • write a class that wraps it (in fact, manual boxing)
  • use an array and access it only directly in the array by index (without copying to a variable); it then speaks directly to the element in the array (without copying).

As an example of the latter;

if(arr[idx].X == 20) SomeMethod(ref arr[idx]); 

Both .X and any use in SomeMethod access the value directly in the array, not the copy. This is only possible with vectors (arrays), not lists.

For one reason, a list of references to structures is impossible: it will allow you to store the address of a variable on the stack in the list; an array usually allocates a variable on the stack, so it would be ridiculously insecure

+5
source

You cannot create references to repositories in C #, but you can create a wrapper of reference type for your value type. However, the overhead associated with copying memory will not be high for a small structure. Profiling revealed that this is a problem?


The following is an example of a value type wrapped in a reference type. Please note that this only works if all access to a specific value is through a reference wrapper type. This violates the standard isolation rules (due to the public field), but this is a bit of a special case.

 public sealed class Reference<T> where T: struct { public T Value; public Reference(T value) { Value = value; } } 

Another thing worth noting is that the Reference shell itself can be null, although its contents are not NULL. You can also add implicit or explicit conversion operators to make this more transparent if you want.

+5
source

If the structures are built from simple types, you can create an array of pointers. Yes, C # pointers are very useful for cases like yours. However, there are limitations. Original structures should be stored in Array , not in List<> . See the example below compiled with the unsafe build flag.

 [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); } } } 

Sorry for the long code, but I wanted to show all the functions of pointers to a structure. The reason List<> will not work is because you cannot take a pointer to a list item. If you really really have to use List<> , _items array from the _items private field with the following code:

  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[]; } 

Be that as it may, it works, and once you have done a reflection on List<> once, you can cache the results in a static field and only call items.GetValue(list) each time.

0
source

Source: https://habr.com/ru/post/903397/


All Articles