在 .NET Platform Invoke 中使用不安全的 struct * 作为不透明类型而不是 IntPtr 是否有效?
.NET Platform Invoke 提倡将指针类型声明为 IntPtr。例如,下面的
[DllImport("mylib")] static extern IntPtr get_foo(); [DllImport("mylib")] static extern void do_something_foo(IntPtr foo);
但是,我发现在与具有许多指针类型的有趣本机接口交互时,将所有内容扁平化为 IntPtr 会使代码非常难以阅读,并删除编译器可以执行的典型类型检查。
我一直在使用一种模式,将不安全的结构声明为不透明的指针类型。我可以将此指针类型存储在托管对象中,编译器可以为我对其进行类型检查。例如:
class Foo { unsafe struct FOO {}; // opaque type unsafe FOO *my_foo; class if { [DllImport("mydll")] extern static unsafe FOO* get_foo(); [DllImport("mydll")] extern static unsafe void do_something_foo(FOO *foo); } public unsafe Foo() { this.my_foo = if.get_foo(); } public unsafe do_something_foo() { if.do_something_foo(this.my_foo); }
注意:我不是在尝试编组结构。 DLL 提供了一个不透明的指针,我不应该触及它,我只需要将它提供给将来对 DLL 的调用。
我知道已发布的执行此操作的方法是 IntPtr,但我不喜欢使用非类型化指针。当有多种指针类型在托管代码和本机代码之间移动时,使用 IntPtrs 是非常危险的。使用我的不透明结构指针类型进行类型检查是天赐之物。
我在实践中使用这种技术没有遇到任何问题。然而,我还没有看到任何人使用这种技术的例子,我想知道为什么。是否有任何原因导致上述代码在 .NET 运行时看来无效?
我的主要问题是.NET GC 系统如何处理“不安全的 FOO *my_foo”。我的希望是,因为底层类型是一个结构体,并且它被声明为不安全,所以 GC 会忽略它。
GC 系统是否会尝试跟踪该指针,或者只是忽略它?使用我的技术代替 IntPtr 安全吗?
.NET Platform Invoke advocates declaring pointer types as IntPtr. For example, the following
[DllImport("mylib")] static extern IntPtr get_foo(); [DllImport("mylib")] static extern void do_something_foo(IntPtr foo);
However, I find when interfacing with interesting native interfaces that have many pointer types, flattening everything into IntPtr makes the code very hard to read and removes the typical typechecking that a compiler can do.
I've been using a pattern where I declare an unsafe struct to be an opaque pointer type. I can store this pointer type in a managed object, and the compiler can typecheck it for me. For example:
class Foo { unsafe struct FOO {}; // opaque type unsafe FOO *my_foo; class if { [DllImport("mydll")] extern static unsafe FOO* get_foo(); [DllImport("mydll")] extern static unsafe void do_something_foo(FOO *foo); } public unsafe Foo() { this.my_foo = if.get_foo(); } public unsafe do_something_foo() { if.do_something_foo(this.my_foo); }
NOTE: I'm not trying to marshal a structure. The DLL is providing an opaque pointer which I'm not supposed to touch, I merely need to provide it to future calls to the DLL.
I know that the published way to do this is IntPtr, but I don't like using an untyped pointer. When there are several pointer types moving between managed and native code, using IntPtrs is very dangerous. Using my opaque struct pointer types for typechecking is a godsend.
I have not run into any trouble using this technique in practice. However, I also have not seen an examples of anyone using this technique, and I wonder why. Is there any reason that the above code is invalid in the eyes of the .NET runtime?
My main question is about how the .NET GC system treats "unsafe FOO *my_foo". My hope is that because the underlying type is a struct, and it's declared unsafe, that the GC would ignore it.
Is this pointer something the GC system is going to try to trace, or is it simply going to ignore it? Is it safe to use my technique instead of IntPtr?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看来答案是“是”......“不安全的指针被视为值类型”,这意味着使用它们来存储不透明类型是安全的。从某种意义上说,它们的工作方式与 IntPtr 类似,但它们带有额外的类型检查,因为不同类型的不安全指针不被视为相同,而如果将它们全部设为 IntPtr,则它们会被视为相同。
有关我就该主题撰写的更详细文章,请查看..
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?waid=1210&aid=339290
It appears that the answer is "yes"... "unsafe pointers are treated as value types", which means it's safe to use them to store opaque types. In a sense, they work just like IntPtr, but they come with additional type-checking, because different types of unsafe pointers are not considered the same, as they would be if you made them all IntPtr.
For a more detailed article I wrote on the topic, check out..
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?waid=1210&aid=339290
我不会使用不安全的代码和指针。为什么不简单地定义结构并让 CLR 进行映射:
然后:
I wouldn't use unsafe code and pointers. Why not simply define the structure and let the CLR do the mapping:
and then: