struct和析构函数

时间:2011-08-21 19:59:50

标签: c#

我创建了类型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#不允许struct拥有destrcutor或覆盖'Finalize'方法,如果IntPtr<T>类型的变量熄灭破坏的范围,但GCHandle不会是免费的。

更新

作为此类用法的一个示例,假设我们要从COAUTHIDENTITY插入COAUTHINFOCOM,这里的内容如下:

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

相反,要使pAuthIdentityData成为IntPtr并使用Marshal成员函数来获取COAUTHIDENTITY类型的对象,IntPtr<T>将使其变得更加简单。

问题是:在GCHandle发布时,我应该在哪里编写代码以免费IntPtr<T>

1 个答案:

答案 0 :(得分:3)

你正在重新发明轮子。看看SafeHandle课程。使用现有的后代或创建自己的后代。