了解 C# 中的非托管关键字

Understanding unmanaged keyword in C#

情况

我正在阅读有关 C# 7.x 到 8.0 中新增功能的 MSDN 文档,并找到了这些文章 (doc1, doc2)

所以我决定创建一个小测试。

代码

Pointer.cs

internal readonly unsafe struct Pointer<T>
    where T : unmanaged
{
    private readonly void* mValue;

    internal Pointer(T value)
    {
        //fixed (T* val = &value) <--- Error: You cannot use the fixed statement to take the adress of an already fixed expression.
        //    mValue = val;

        mValue = &value;
    }

    public static implicit operator Pointer<T>(T value)
    {
        return new Pointer<T>(value);
    }

    public static implicit operator string(Pointer<T> value)
    {
        var ptr = (T*)value.mValue;
        return ptr->ToString(); // returns random values (maybe adresses).
    }
}

Program.cs

class Program
{
    static void Main(string[] args)
    {
        Pointer<int> ptr = 2;

        Console.WriteLine(ptr); // prints random values (maybe adresses).
    }
}

问题

为什么不允许我在构造函数中使用 fixed 语句。我的意思是这是有道理的,它会抛出一个错误。我说过 T 应该是 unmanaged,所以我认为它在内部自动使用 fixed 关键字。但是如果它这样做那么为什么我得到随机值。

根据 documentation for unmanaged types T 将是某种不能包含对托管类型的引用的值类型。因此它将分配在堆栈上。当构造函数 returns 时,堆栈将被弹出,指针将指向某个未定义的值。您不能对堆栈上分配的内容使用 fixed,因为无论如何都不能被垃圾收集器移动,因此被认为是 'fixed'。

我对正在发生的事情的理解:

  1. 这里你得到了堆栈中 int 的按值副本。

    internal Pointer(T value)
    
  2. 这里取一个指向栈中int的指针。

    mValue = &value;
    
  3. 然后构造函数完成,int 从堆栈中弹出,指针是孤立的。

  4. 其他东西被放在堆栈上,例如Pointer<T>结构本身,指针现在导致垃圾。

    public static implicit operator string(Pointer<T> value)
    
  5. 你把垃圾读成int

    var ptr = (T*)value.mValue;