Понимание неуправляемого ключевого слова в C# - PullRequest
3 голосов
/ 22 апреля 2020

Ситуация

Я читал документы MSDN о том, что нового в C# 7.x до 8.0, и нашел эти статьи ( 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 для внутреннего использования. НО, если это так, то почему я получаю случайные значения.

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Мое понимание происходящего:

  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;
    
1 голос
/ 22 апреля 2020

Согласно документации для неуправляемых типов T будет своего рода типом значения, который не может содержать ссылки на управляемые типы. Как таковой он будет размещен в стеке. Когда конструктор вернется, стек будет вытолкнут, а указатель будет указывать на какое-то неопределенное значение. Вы не можете использовать fixed для чего-то, выделенного в стеке, так как сборщик мусора в любом случае не может быть перемещен, и поэтому считается «фиксированным».

...