2011-08-21 178 views
1

我創建的類型IntPtr<T>表現得像一個普通指針的C/C++有:結構和析構函數

public struct IntPtr<T> : IDisposable where T : struct 
{ 
    private static Dictionary<IntPtr, GCHandle> handles = new Dictionary<IntPtr, GCHandle>(); 

    private IntPtr ptr; 

    public IntPtr(ref T value) 
    { 
     GCHandle gc = GCHandle.Alloc(value, GCHandleType.Pinned); 

     ptr = gc.AddrOfPinnedObject(); 
     handles.Add(ptr, gc); 
    } 

    public IntPtr(ref T[] value) 
    { 
     GCHandle gc = GCHandle.Alloc(value, GCHandleType.Pinned); 

     ptr = gc.AddrOfPinnedObject(); 
     handles.Add(ptr, gc); 
    } 

    public IntPtr(IntPtr value) 
    { ptr = value; } 

    public IntPtr(IntPtr<T> value) 
    { ptr = value.ptr; } 

    public void Dispose() 
    { 
     if (handles.ContainsKey(ptr)) 
     { 
      GCHandle gc = handles[ptr]; 
      gc.Free(); 
      handles.Remove(ptr); 
      ptr = IntPtr.Zero; 
     } 
    } 

    public T? this[int index] 
    { 
     get 
     { 
      if (ptr == IntPtr.Zero) return null; 
      if (index < 0) throw new IndexOutOfRangeException(); 

      if (handles.ContainsKey(ptr)) 
      { 
       GCHandle gc = handles[ptr]; 

       if (gc.Target is Array) return ((T[])gc.Target)[index]; 

       return (T)gc.Target; 
      } 

      return null; 

     } 
     set 
     { 
      if (index < 0) throw new IndexOutOfRangeException(); 
      // not yet implemented 
     } 
    } 

    private T[] getArray() 
    { 
     if (handles.ContainsKey(ptr)) return (T[])handles[ptr].Target; 

     return null; 
    } 

    public int Count 
    { 
     get 
     { 
      if(handles.ContainsKey(ptr)) 
      { 
       GCHandle gc = handles[ptr]; 
       if (gc.Target is Array) return ((T[])gc.Target).Length; 

       return 1; 
      } 

      return 0; 
     } 
    } 

    public static implicit operator IntPtr(IntPtr<T> value) { return value.ptr; } 

    public static implicit operator T(IntPtr<T> value) { return (T)value[0]; } 

    public static implicit operator T[](IntPtr<T> value) { return value.getArray(); ; } 

    public static implicit operator T?(IntPtr<T> value) { return value[0]; } 

} 

它尚未完成,但現在它的工作原理,問題是我通過存儲保持GCHandle跟蹤他們handles現在我需要釋放GCHandle一旦沒有更多的需要的,所以我必須聲明一個destrcutor但是C#不允許structdestrcutor或重寫「終結」的方法,如果IntPtr<T>類型的這種變量超出破壞發生的範圍,但GCHandle將不會免費。

UPDATE

由於這類用途的例子,假設我們打算從COM interpo COAUTHIDENTITYCOAUTHINFO,這裏將是什麼樣子:

[StructLayout(LayoutKind.Sequential)] 
struct COAUTHIDENTITY 
{ 
    [MarshalAs(UnmanagedType.LPWStr)] string User; 
    uint UserLength; 
    [MarshalAs(UnmanagedType.LPWStr)] string Domain; 
    uint DomainLength; 
    [MarshalAs(UnmanagedType.LPWStr)] string Password; 
    uint PasswordLength; 
    uint Flags; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct COAUTHINFO 
{ 
    uint dwAuthnSvc; 
    uint dwAuthzSvc; 
    [MarshalAs(UnmanagedType.LPWStr)] string pwszServerPrincName; 
    uint dwAuthnLevel; 
    uint dwImpersonationLevel; 
    IntPtr<COAUTHIDENTITY> pAuthIdentityData; 
    uint dwCapabilities; 
} 

反而使pAuthIdentityDataIntPtr並使用Marshal成員函數來獲取COAUTHIDENTITY類型的對象,IntPtr<T>將使其更簡單。

現在的問題是:我應該在IntPtr<T>發佈時,在哪裏寫代碼以釋放GCHandle

+1

只是...爲什麼?你在這裏試圖做什麼?既然你已經限制了'T:struct',你已經有了基於範圍的生命週期...?或者如果它*是一個類,那麼假設(從這裏的用法來看)它是短暫的,它將被收集在第0代*反正*中,這是非常便宜的。 –

+0

嗯...這個班應該是類似於IntPtr的類型嗎? IntPtr不會跟蹤生命週期,它只是一個像C指針一樣的指針。 – Skurmedel

+1

參見上面的示例 –

回答

3

您正在重新發明輪子。看看SafeHandle課程。使用現有的後代或創建自己的後代。

+1

SafeHandle是一個操作系統句柄,不是指向任何數據的指針。 –

+1

@穆罕默德:好點。你可能想看看[GCHandles的真相](http://blogs.msdn.com/b/clyon/archive/2005/03/18/398795.aspx)有關GCHandles和拳擊的風險。 – TrueWill