我正在尝试定义一个属性,该属性返回指向泛型类型参数的指针,如下所示:
编译器报错,指针不能声明为托管类型 T 或获取其地址或大小 (CS0208)。奇怪的是,如果我手动用具体的结构替换泛型类型参数,则不会出现以上问题。
一切都编译得很好。但是,我将不得不为我使用的每个结构创建一个专门的包装器版本。那么,通用型为什么还要关心它转换的不安全指针类型呢?
背景信息:我正在使用本地dll,该dll调用我的c#回调函数并传递给它我的最通用用户数据结构作为指针(更精确地说:伪装成IntPtr)。为了能够传递GC稳定的指针,我在非托管堆上分配了我的用户数据结构。因此,最后我必须确保内存被释放。
由于这当然超出了忠实的c#程序员所能承受的范围,所以我正在创建一个包装器类(围绕堆分配和结构指针的使用),尽可能地与丑陋的东西隔离开来。为了尽可能轻松地为非托管堆上的结构分配值,我想定义上述属性。
当然,使用unsafe属性只是一个轻微的便利改进(比直接返回不明确的IntPtr并从外部将其转换为不安全指针),因此可能不值得一试所有成本。但既然问题已经摆在桌面上,我想了解一下。
编辑:看起来问题是我假设结构仅由值类型组成,这使我能够确定其大小并在堆上分配它。在专门的版本中,结构的组成确实为编译器所知。
但是,在泛型版本中,结构也可以由引用类型(即托管类型)组成,尽管由于上述原因,我永远不会这样做。除非我能编写一个泛型约束,例如“where T:struct由值类型组成”,否则我似乎很倒霉...
public class MemWrapper<T> where T: struct
{
readonly IntPtr pointerToUnmanagedHeapMem;
// ... do some memory management also ...
public unsafe T* Ptr
{
get {return (T*)(pointerToUnmanagedHeapMem);}
}
}
编译器报错,指针不能声明为托管类型 T 或获取其地址或大小 (CS0208)。奇怪的是,如果我手动用具体的结构替换泛型类型参数,则不会出现以上问题。
public class MyStructMemWrapper
{
readonly IntPtr pointerToUnmanagedHeapMem;
// ... do some memory management also ...
public unsafe MyStruct* Ptr
{
get {return (MyStruct*)(pointerToUnmanagedHeapMem);}
}
}
一切都编译得很好。但是,我将不得不为我使用的每个结构创建一个专门的包装器版本。那么,通用型为什么还要关心它转换的不安全指针类型呢?
背景信息:我正在使用本地dll,该dll调用我的c#回调函数并传递给它我的最通用用户数据结构作为指针(更精确地说:伪装成IntPtr)。为了能够传递GC稳定的指针,我在非托管堆上分配了我的用户数据结构。因此,最后我必须确保内存被释放。
由于这当然超出了忠实的c#程序员所能承受的范围,所以我正在创建一个包装器类(围绕堆分配和结构指针的使用),尽可能地与丑陋的东西隔离开来。为了尽可能轻松地为非托管堆上的结构分配值,我想定义上述属性。
public struct MyStruct {public double x;}
// ...
MemWrapper<MyStruct> m = new MemWrapper<MyStruct>();
unsafe
{
// ideally I would like to get rid of the whole
// bloody unsafe block and directly write m.x = 1.0
m.Ptr->x = 1.0;
}
当然,使用unsafe属性只是一个轻微的便利改进(比直接返回不明确的IntPtr并从外部将其转换为不安全指针),因此可能不值得一试所有成本。但既然问题已经摆在桌面上,我想了解一下。
编辑:看起来问题是我假设结构仅由值类型组成,这使我能够确定其大小并在堆上分配它。在专门的版本中,结构的组成确实为编译器所知。
但是,在泛型版本中,结构也可以由引用类型(即托管类型)组成,尽管由于上述原因,我永远不会这样做。除非我能编写一个泛型约束,例如“where T:struct由值类型组成”,否则我似乎很倒霉...
void Foo<T>(T bar) where T : struct
来创建一个方法。 - FCinpublic unsafe MyStruct* Ptr
的声明已经被成功编译。 - Alexey Klipilin