2011-03-22 12 views
5

Estoy implementando una clase de matriz no administrada en C# que necesito para algunas llamadas OpenGL.Implementación de una matriz genérica no administrada en C#

Va muy bien, pero he dado en un obstáculo. El siguiente código no se compila, y entiendo por qué, pero ¿cómo puedo hacerlo funcionar?

public T this[int i] 
    { 
     get { return *((T*)arrayPtr + i); } 
     set { *((T*)arrayPtr + i) = value; } 
    } 

pensé que podría funcionar si me aseguré de que T es una estructura

unsafe class FixedArray<T> where T : struct 

no funciona bien ...

¿Cómo puedo conseguir algo funcionalmente a lo que equivilant Estoy tratando de hacer lo anterior?

EDITAR: Estoy usando una matriz no administrada con Marshal.AllocHGlobal() para que mi arreglo sea fijo y el GC no lo mueva. OpenGL en realidad no procesa las instrucciones cuando lo llamas, OpenGL intentará acceder a la matriz mucho después de que la función haya regresado.

Aquí está toda la clase si eso ayuda:

unsafe class FixedArray<T> where T : struct 
{ 
    IntPtr arrayPtr; 

    public T this[int i] 
    { 
     get { return *((T*)arrayPtr + i); } 
     set { *((T*)arrayPtr + i) = value; } 
    } 
    public FixedArray(int length) 
    { 
     arrayPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * length); 
    } 
    ~FixedArray() 
    { 
     Marshal.FreeHGlobal(arrayPtr); 
    } 
} 

El mensaje de error es no puede tomar la dirección de, obtener el tamaño de, o declarar un puntero a un tipo administrado ('T')

+1

Por favor, incluya el mensaje de error. – Richard

+2

¿Estás seguro de que necesitas una matriz no administrada? – Gabe

+0

Sí, estoy seguro. Lo intenté por primera vez y obtuve AccessViolationExceptions. – Hannesh

Respuesta

5

Estoy bastante seguro de que no es posible compilar el código. Para su código (T*)arrayPtr + i, esto calcularía arrayPtr + i * 4 cuando T es un int y arrayPtr + i * 8 cuando T es un long. Como el CLR no tiene forma de sustituir un 4, 8, o lo que sea sizeof(T), este código simplemente no puede funcionar.

Lo que necesita hacer es usar Marshal para hacer todo el trabajo por usted. Esto compila, pero no lo he probado:

unsafe class FixedArray<T> where T : struct 
{ 
    IntPtr arrayPtr; 

    int sizeofT { get { return Marshal.SizeOf(typeof(T)); } } 

    public T this[int i] 
    { 
     get 
     { 
      return (T)Marshal.PtrToStructure(arrayPtr + i * sizeofT, typeof(T)); 
     } 
     set 
     { 
      Marshal.StructureToPtr(value, arrayPtr + i * sizeofT, false); 
     } 
    } 
    public FixedArray(int length) 
    { 
     arrayPtr = Marshal.AllocHGlobal(sizeofT * length); 
    } 
    ~FixedArray() 
    { 
     Marshal.FreeHGlobal(arrayPtr); 
    } 
} 
+2

Esta solución * copiará * las estructuras dentro y fuera del bloque de memoria cada vez 'this [] 'se usa, por lo que las afirmaciones razonables como' fixedArray [3] .Data = 3; 'no funcionarán como se espera. Si desea hacerlo de esta manera, también debe implementar 'Dispose' y usar' GC.AddMemoryPressure'. –

+0

Parece bastante sólido, lo intentaré cuando llegue a casa. Tengo experiencia con C y con C#.Pero C# no administrado es nuevo para mí. – Hannesh

4

No necesita una matriz no administrada.

Puede declarar una matriz administrada normalmente:

var myArray = new MyStruct[13]; 

y luego utilizar la clase GCHandle para fijarlo en la memoria y obtener su dirección:

var handle = GCHandle.Alloc(myArray, GCHandleType.Pinned); 
IntPtr address = handle.AddrOfPinnedObject(); 

La matriz existirá en esa dirección de memoria hasta que llame al handle.Free. Si nunca llama al Free, permanecerá allí hasta que finalice su programa.

+0

¿Cómo se compara el rendimiento de esto con el ejemplo de Gabe? ¿Está bien anotar muchas matrices grandes en la memoria administrada del recolector de basura? – Hannesh

+1

El rendimiento es una propiedad matizada. Pinning arrays reducirá la eficiencia del GC; si tendrá "demasiado" impacto solo se puede determinar con la prueba. La respuesta de Gabe no afectará tanto al GC (siempre que use 'Dispose' y' AddMemoryPressure' como lo recomiendo), pero agrega sobrecarga al modificar las matrices. –

Cuestiones relacionadas