Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 返回类型参数的不安全指针_C#_Generics_Unmanaged_Unsafe - Fatal编程技术网

C# 返回类型参数的不安全指针

C# 返回类型参数的不安全指针,c#,generics,unmanaged,unsafe,C#,Generics,Unmanaged,Unsafe,我试图定义一个属性,该属性返回指向泛型类型参数的指针,如下所示: public class MemWrapper<T> where T: struct { readonly IntPtr pointerToUnmanagedHeapMem; // ... do some memory management also ... public unsafe T* Ptr { get {return (T*)(pointerToUnmana

我试图定义一个属性,该属性返回指向泛型类型参数的指针,如下所示:

public class MemWrapper<T> where T: struct
{
    readonly IntPtr pointerToUnmanagedHeapMem;

    // ... do some memory management also ...

    public unsafe T* Ptr
    {
        get {return (T*)(pointerToUnmanagedHeapMem);}
    }
}
一切都很好。但是接下来我必须为我使用的每个结构创建一个专门的包装器版本。那么,为什么泛型甚至关心它正在抛出什么样的不安全指针呢

背景信息:我使用的是一个本机dll,它反过来调用我的c#callback函数,并将我最常用的用户数据结构作为指针传递给它(更准确地说:伪装成IntPtr)。为了能够传递一个GC稳定指针,我在非托管堆上分配我的用户数据结构。因此,我必须注意,记忆最终会再次被释放

由于这当然是一个专门的c#程序员所能承受的极限,我正在创建一个包装类(围绕堆分配和指向struct的指针的使用),它尽可能地将我与丑陋的东西分开。为了尽可能容易地为非托管堆上的结构赋值,我想定义上面的属性

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;
}
public struct MyStruct{public double x;}
// ...
MemWrapper m=newmemwrapper();
不安全的
{
//理想情况下,我想摆脱整个
//不安全块,直接写入m.x=1.0
m、 Ptr->x=1.0;
}
当然,不安全属性只是一个小小的便利性改进(与直接返回不特定的IntPtr并从外部将其转换为不安全指针相比),因此它可能不值得付出任何代价。但现在问题摆在桌面上,我想理解它

Edit:问题似乎在于,我假设结构仅由值类型组成,这允许我确定其大小,并在堆上分配它。在专用版本中,编译器确实知道结构的组成


然而,在泛型版本中,结构也可以由引用(即托管)类型组成,尽管由于上述原因,我永远不会这样做。除非我能够编写一个泛型约束,如“其中T:struct由值类型组成”,否则我似乎运气不好……

泛型和指针不能很好地协同工作,但这实际上非常适合“ref return”:

请注意,这需要最新版本的
不安全
;在这里,我使用:

<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
没有非托管指针;代码现在在
.Ptr
之外完全“安全”


注意:如果您需要谈论多个连续项目:
Span
/
内存
是您的朋友。

您将无法做到这一点。非常清楚“不允许声明指向托管类型的指针”。但是您可以尝试使用restriction
void Foo(T bar)创建一个方法,其中T:struct
@FCin但是
public不安全的MyStruct*Ptr
声明是编译的ok@Alexey但是MyStruct是一种值类型,它不包含任何引用types@FCin好的,现在看起来很清楚,你要做的是确保T是1。值类型(其中T:struct)2。T没有任何引用类型字段(没有办法限制)。哇,这看起来很有希望!但我不能让它工作。我在声明中的ref关键字处得到CS1031。我也不知道如何做包的东西-使用框架4.5.2是不够的?另外,我正在使用SharpDevelop。。。这是Visual Studio特有的吗?@oliver它需要C#7,那么:SharpDevelop是否有最新的编译器支持
ref return
不是Visual Studio特有的,也不是任何.NET版本特有的,但它确实需要C#7。@oliver reading,而且,在SharpDevelop中获得C#7的可能性很小;您可能希望考虑(轻量级和免费)或(更完整的IDE和免费的)
public class MemWrapper<T> where T : struct
{
    readonly IntPtr pointerToUnmanagedHeapMem;

    // ... do some memory management also ...

    public unsafe ref T Ptr
    {
        get { return ref Unsafe.AsRef<T>(pointerToUnmanagedHeapMem.ToPointer()); }
    }
}
public unsafe ref T Ptr => ref Unsafe.AsRef<T>(pointerToUnmanagedHeapMem.ToPointer());
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
var wrapper = ... // some MemWrapper<T>
ref Foo foo = ref wrapper.Ptr;
Console.WriteLine(foo.SomeProperty); // not foo->SomeProperty
SomeInnerMethod(ref foo); // pass down to other ref Foo methods