C# 使用类类型的DebuggerTypeProxy时类型不匹配
这是一个相当复杂的问题,请耐心听我说 我定义了一个用作非托管数组的结构。因为我正在使用(并且一直坚持使用)C#7.3,所以带有非托管约束的泛型结构被视为托管类型。这意味着我不能获取或使用指向此结构的指针。因此,非托管数组未声明为泛型。为了具有类型安全性,在调用(伪)构造函数时,泛型类型的TypeHandle与对象一起存储。对于每个后续调用,将泛型的TypeHandle与存储的TypeHandle进行比较,以断言它是相同的类型 接下来,我将这个非托管数组包装到另一个通用对象中。这大大简化了对非托管阵列的API调用。由于无法看到指针中存储的内容,因此我制作了一个DebuggerTypeProxy,用于将非托管数组转换为托管数组。因此,在调试期间,您可以查看非托管阵列的内容 现在问题终于来了。将此DebuggerTypeProxy定义为类时,非托管数组调用的TypeHandles之间不匹配。但是,将DebuggerRypeProxy定义为结构时,不存在不匹配。这里到底发生了什么 下面是一些用于实现的代码,以澄清我所做的工作。它被大幅删减,只显示相关部分C# 使用类类型的DebuggerTypeProxy时类型不匹配,c#,pointers,unmanaged,typehandler,C#,Pointers,Unmanaged,Typehandler,这是一个相当复杂的问题,请耐心听我说 我定义了一个用作非托管数组的结构。因为我正在使用(并且一直坚持使用)C#7.3,所以带有非托管约束的泛型结构被视为托管类型。这意味着我不能获取或使用指向此结构的指针。因此,非托管数组未声明为泛型。为了具有类型安全性,在调用(伪)构造函数时,泛型类型的TypeHandle与对象一起存储。对于每个后续调用,将泛型的TypeHandle与存储的TypeHandle进行比较,以断言它是相同的类型 接下来,我将这个非托管数组包装到另一个通用对象中。这大大简化了对非托管
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并查看其内容时,它工作得非常好。只有在以下情况下,才会发生断裂: