2011-03-22 26 views
5

我正在C#中實現一個非託管數組類,我需要一些OpenGL調用。在C中實現一個通用的非託管數組#

這很好,但我遇到了障礙。下面的代碼不能編譯,我明白爲什麼,但我怎麼才能使它工作?

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

我認爲可能的工作,如果我保證T是一個結構

unsafe class FixedArray<T> where T : struct 

不工作,要麼...

我怎樣才能得到的東西功能equivilant什麼,我上面想要做什麼?

編輯:我正在使用與Marshal.AllocHGlobal()的非託管數組,以便我的數組是固定的,GC不會移動它。 OpenGL在調用它時並不實際處理指令,OpenGL將在函數返回後嘗試訪問數組。

這裏是全班同學是否有幫助:

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

該錯誤消息無法獲取地址,得到的大小,或宣佈一個指向託管類型(「T」)

+1

請包含錯誤消息。 – Richard 2011-03-22 08:03:00

+2

你確定你需要一個非託管數組嗎? – Gabe 2011-03-22 08:06:07

+0

是的,我確定。我第一次嘗試它沒有得到AccessViolationExceptions。 – Hannesh 2011-03-22 08:12:08

回答

5

我敢肯定,讓你的代碼編譯是不可能的。對於您的代碼(T*)arrayPtr + i,這將計算arrayPtr + i * 4TintarrayPtr + i * 8Tlong。由於CLR無法替代4,8或任何sizeof(T)碰巧是,這個代碼就無法工作。

您需要做的是使用Marshal爲您完成所有工作。這編譯,但我沒有測試它:

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

此解決方案將每次在this []中將結構複製到內存塊和從內存塊中移出[ '被使用,所以像'fixedArray [3] .Data = 3;'這樣的合理的語句將無法按預期工作。如果你想這樣做,你也應該實現'Dispose'並使用'GC.AddMemoryPressure'。 – 2011-03-22 11:15:57

+0

看起來很不錯,我會在我回家的時候嘗試一下。我有C和C#的經驗。但是,非託管C#對我來說是新的。 – Hannesh 2011-03-22 11:16:09

4

你不需要一個非託管數組。

可以正常聲明託管數組:

var myArray = new MyStruct[13]; 

,然後使用GCHandle類別針把它在內存中,並得到其地址:

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

的陣列將在內存地址存在直到您致電handle.Free。如果你永遠不會撥打Free,那麼它會一直呆在那裏直到你的程序退出。

+0

這與Gabe的例子相比,表現如何。在垃圾收集器的託管內存中固定很多大型數組可以嗎? – Hannesh 2011-03-22 17:39:14

+1

表現是一個細微的屬性。固定陣列會降低GC的效率;它是否會產生「太多」的影響只能通過測試來確定。 Gabe的回答不會像GC那樣影響GC(只要按照我的建議使用Dispose和AddMemoryPressure),但在修改陣列時會增加開銷。 – 2011-03-22 20:25:31

相關問題