2013-12-16 61 views
7

有一個方法來double[] d轉換爲IntPtr,如:做出什麼樣的陣列只有一個方法的IntPtr

public static IntPtr DoubleArrayToIntPtr(double[] d) 
{ 
    IntPtr p = Marshal.AllocCoTaskMem(sizeof(double) * d.Length); 
    Marshal.Copy(d, 0, p, d.Length); 
    return p; 
} 

什麼是使int[]float[],等我想上做的最好辦法對於每種類型的一個方法,如添加INT []:

public static IntPtr IntArrayToIntPtr(int[] d) 
{ 
    IntPtr p = Marshal.AllocCoTaskMem(sizeof(int) * d.Length); 
    Marshal.Copy(d, 0, p, d.Length); 
    return p; 
} 

1.可這方法一概而論,如果又如何?

2.是否有可能只在一行代碼中獲取指針(因爲元帥是void方法)?

+2

你需要什麼intptr爲 - 確定如何編組。 –

+1

你真的想要一個副本,或者只是[指向固定數組的指針](http://stackoverflow.com/a/4097057/11683)? – GSerg

+0

文字轉換模板工具包。簡稱T4。 – Theraot

回答

4

最好的辦法是做一個擴展類,爲你做,爲每種類型。由於Marshal.Copy()不支持泛型,因此不能使其通用。所以,你必須重複你的方法對每種類型bytecharintlongfloatdouble等。但是,你可以爲你的決定大小Marshsal一個通用的helper方法。

類似下面可能對你有用:

public static class MarshalExtender 
{ 
    public static IntPtr CopyToCoTaskMem(this byte[] array) 
    { 
     var ptr = AllocArrayCoTaskMem(array); 

     Marshal.Copy(array, 0, ptr, array.Length); 
     return ptr; 
    } 

    // Copy the above method and replace types as needed (int, double, etc). 

    // Helper method for allocating bytes with generic arrays. 
    static IntPtr AllocArrayCoTaskMem<T>(T[] array) 
    { 
     var type = typeof(T); 
     var size = Marshal.SizeOf(type) * array.Length; 
     return Marshal.AllocCoTaskMem(size); 
    } 
} 

主要的好處是在你的代碼,你可以很容易地做一些事情,如:

var myArray = { 0, 1, 2, 3, 4, 5, ... } 
var ptr = myArray.CopyToCoTaskMem(); 

注:只是一定要打電話Marshal.FreeCoTaskMem()當你完成它!我建議你的擴展方法返回一個IDisposable對象,這樣你可以將它包裝在using塊中。

例如:

public sealed class CoTaskMemoryHandle : IDisposable 
{ 
    bool isDisposed; 
    readonly IntPtr handle; 

    public IntPtr Handle { get { return handle; } } 

    public CoTaskMemoryHandle(IntPtr handle) 
    { 
     this.handle = handle; 
    } 

    public void Dispose() 
    { 
     OnDispose(true); 
     GC.SuppressFinalize(this); 
    } 

    void OnDispose(bool isDisposing) 
    { 
     if (isDisposed) return; 

     if (isDisposing) 
     { 
      if (handle != IntPtr.Zero) 
       Marshal.FreeCoTaskMem(handle); 
     } 

     isDisposed = true; 
    } 
} 

然後修改後的擴展類方法:

public static CoTaskMemoryHandle CopyToCoTaskMem(this byte[] array) 
{ 
    var ptr = AllocArrayCoTaskMem(array); 

    Marshal.Copy(array, 0, ptr, array.Length); 
    return new CoTaskMemoryHandle(ptr); 
} 

這樣,您就可以放心地封裝Alloc/Free平衡:

using(myArray.CopyToCoTaskMem()) 
{ 
    // Do something here.. 
} 
+1

我建議繼承['SafeHandleZeroOrMinusOneIsInvalid'](http://msdn.microsoft.com/ru-ru/library/microsoft.win32.safehandles。 safehandlezeroorminusoneisinvalid.aspx)而不是'IDisposable'。 – GSerg

+0

是的!我只是在想這個! – Erik

2

要回答你的第一個問題,是的,它可以被概括:

public static IntPtr ArrayToIntPtr<T>(T[] d) where T : struct 
{ 
    var arrayType = typeof(T); 
    IntPtr p = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(T)) * d.Length); 
    if (arrayType == typeof(int)) 
    { 
      Marshal.Copy((int[])(object)d, 0, p, d.Length); 
    } 
    //else if ....other types you want to handle 
    return p; 
} 

我加了結構的類型約束,這限制了你的值類型(短褲,雙打,整數,結構)。你顯然需要注意你在那裏傳遞的內容(就像你傳遞一個結構體一樣)。爲了解決你的第二個問題,不,我認爲你不能將這個問題簡化爲一行,即使可以,也可能不希望爲了提高可讀性。

編輯
我已經通過固定發射井在評論中發現的問題,但是這個代碼是現在很醜陋,我不能說我會推薦這種方法。它顯然涉及很多類型檢查和拳擊,以獲得正確的類型。事實上,我個人建議在Silo的answer之上,儘管我已經證明你可以用一般的方式做到這一點,儘管肯定會打破仿製藥的精神。

+2

與此有關的幾個問題。首先你會得到'sizeof'的警告,需要在** unsafe **上下文中使用,這是不推薦的。應該使用'Marshal.SizeOf()'來代替。即使如此,'Marshal.Copy'不支持泛型參數,這是行不通的。 – Erik

+0

@SiLo這就是我在SO編寫代碼而不是在實際的C#編輯器中得到的 –

+0

沒問題,我傾向於這樣做,有時候我會理解。我對此很好奇,所以我開始VS看。不幸的是,這並不簡單。 :(看起來像單獨的重載是必需的,但它們可能是相當小的方法。 – Erik

相關問題