C# 使用类类型的DebuggerTypeProxy时类型不匹配

C# 使用类类型的DebuggerTypeProxy时类型不匹配,c#,pointers,unmanaged,typehandler,C#,Pointers,Unmanaged,Typehandler,这是一个相当复杂的问题,请耐心听我说 我定义了一个用作非托管数组的结构。因为我正在使用(并且一直坚持使用)C#7.3,所以带有非托管约束的泛型结构被视为托管类型。这意味着我不能获取或使用指向此结构的指针。因此,非托管数组未声明为泛型。为了具有类型安全性,在调用(伪)构造函数时,泛型类型的TypeHandle与对象一起存储。对于每个后续调用,将泛型的TypeHandle与存储的TypeHandle进行比较,以断言它是相同的类型 接下来,我将这个非托管数组包装到另一个通用对象中。这大大简化了对非托管

这是一个相当复杂的问题,请耐心听我说

我定义了一个用作非托管数组的结构。因为我正在使用(并且一直坚持使用)C#7.3,所以带有非托管约束的泛型结构被视为托管类型。这意味着我不能获取或使用指向此结构的指针。因此,非托管数组未声明为泛型。为了具有类型安全性,在调用(伪)构造函数时,泛型类型的TypeHandle与对象一起存储。对于每个后续调用,将泛型的TypeHandle与存储的TypeHandle进行比较,以断言它是相同的类型

接下来,我将这个非托管数组包装到另一个通用对象中。这大大简化了对非托管阵列的API调用。由于无法看到指针中存储的内容,因此我制作了一个DebuggerTypeProxy,用于将非托管数组转换为托管数组。因此,在调试期间,您可以查看非托管阵列的内容

现在问题终于来了。将此DebuggerTypeProxy定义为类时,非托管数组调用的TypeHandles之间不匹配。但是,将DebuggerRypeProxy定义为结构时,不存在不匹配。这里到底发生了什么

下面是一些用于实现的代码,以澄清我所做的工作。它被大幅删减,只显示相关部分

public unsafe struct UnsafeArray
{
    void* _buffer;

    int _length;
    IntPtr _typeHandle;

    //Pseudo-constructor
    public static UnsafeArray* Allocate<T>(int size) where T : unmanaged
    {
        //Do a lot of allocation stuff...
        UnsafeArray* array;

        //Storing the typehandle of the type that is used to construct the unmanaged array
        array->_typeHandle = typeof(T).TypeHandle.Value;

        return array;
    }

    //One of the methods that operates on the UnsafeArray
    public static T* GetPtr<T>(UnsafeArray* array, long index) where T : unmanaged
    {
        UDebug.Assert(array != null);
        
        //This assertion fails!!
        UDebug.Assert(typeof(T).TypeHandle.Value == array->_typeHandle);

        // cast to uint trick, which eliminates < 0 check
        if ((uint)index >= (uint)array->_length)
        {
            throw new IndexOutOfRangeException(index.ToString());
        }

        return (T*)array->_buffer + index;
    }
}
公共不安全结构
{
void*\u缓冲区;
整数长度;
IntPtr_型手柄;
//伪构造函数
公共静态数组*分配(整数大小),其中T:非托管
{
//做很多分配工作。。。
射线*阵列;
//存储用于构造非托管数组的类型的typehandle
数组->\u typeHandle=typeof(T).typeHandle.Value;
返回数组;
}
//在光线上操作的方法之一
公共静态T*GetPtr(数组,长索引),其中T:unmanaged
{
Assert(数组!=null);
//这个断言失败了!!
Assert(typeof(T).TypeHandle.Value==array->\u TypeHandle);
//施放到uint技巧,消除<0检查
if((uint)索引>=(uint)数组->\u长度)
{
抛出新的IndexOutOfRangeException(index.ToString());
}
返回(T*)数组->缓冲区+索引;
}
}
以下是在内部使用NativeArray的包装器

[DebuggerDisplay("Length = {Length}")]
[DebuggerTypeProxy(typeof(Debug.TypeProxies.NativeArrayDebugView<>))]
public unsafe struct NativeArray<T> : IDisposable, IEnumerable<T>, IEnumerable where T : unmanaged
{
    private UnsafeArray* m_inner;

    public T[] ToArray()
    {
        var arr = new T[Length];

        Copy(this, 0, arr, 0, arr.Length);

        return arr;
    }
    //A lot of other stuff....
}
[DebuggerDisplay(“Length={Length}”)]
[DebuggerTypeProxy(typeof(Debug.TypeProxies.NativeArrayDebugView))]
公共不安全结构NativeArray:IDisposable、IEnumerable、IEnumerable其中T:非托管
{
列兵:雷*穆内;
公共T[]ToArray()
{
var arr=新的T[长度];
副本(此,0,arr,0,arr.Length);
返回arr;
}
//还有很多其他的东西。。。。
}
最后,DebuggerTypeProxy使用的类型

internal struct NativeArrayDebugView<T> where T : unmanaged
{
    private readonly NativeArray<T> m_array;

    public NativeArrayDebugView(NativeArray<T> array)
    {
        m_array = array;
    }

    public T[] Items
    {
        get
        {
            if (!m_array.IsCreated)
                throw new System.NullReferenceException();

            //This fails as it makes an internal call to the UnsafeArray with the wrong type!
            return m_array.ToArray();
        }
    }
}
internal struct NativeArrayDebugView其中T:unmanaged
{
专用只读本地阵列m_阵列;
公共NativeArray BugView(NativeArray阵列)
{
m_数组=数组;
}
公共T[]项目
{
得到
{
如果(!m_array.IsCreated)
抛出新的System.NullReferenceException();
//这会失败,因为它会使用错误的类型对不安全的用户进行内部调用!
返回m_array.ToArray();
}
}
}
最后,值得一提的是,当手动创建NativeArrayDebugView并查看其内容时,它工作得非常好。只有在以下情况下,才会发生断裂:

  • NativeArrayDebugView是一个类
  • 查看NativeArray时,可通过调试视图访问NativeArray BugView
  • 我知道这是一个很长很复杂的问题,所以如果有人需要澄清,我很乐意提供