Присвоение значения структуры этому ключевому слову - PullRequest
7 голосов
/ 06 апреля 2011

Недавно я просматривал внутреннюю структуру CancellationToken и обнаружил немного странную конструкцию (точнее, присвоение значения ключевому слову this).

Код одного из его конструкторов:следующим образом:

public CancellationToken( bool canceled )
{
    this = new CancellationToken();
    if ( canceled )
    {
        this.m_source = CancellationTokenSource.InternalGetStaticSource( canceled );
    }
}

Что означает строка, в которой происходит присвоение ключевому слову this?

Обратите внимание, что присвоение ключевому слову this невозможно для классов -возникает ошибка Cannot assign to '<this>' because it is read-only.

Ответы [ 2 ]

7 голосов
/ 06 апреля 2011

Это очень малоизвестная особенность C # - она ​​позволяет структуре перезаписывать свои собственные данные.Я не уверен, доступно ли это только для blittable типов значений или нет (я догадываюсь, нет).

Что касается практического применения, вы не найдете много вариантов для этого ..

struct MyStruct
{
    int a = 1;
    int b = 2;
    int c = 3;

    public void Mutate()
    {
        a = 10;
        b = 20;
        c = 30;
    }

    public void Reset()
    {
        a = 1;
        b = 2;
        c = 3;
    }

    public void Reset2()
    {
        this = new MyStruct();
    }

    // The two Reset methods are equivilent...
}

Думая об этом больше, есть фундаментальное различие в том, что означает "это", когда вы имеете дело с типами значений против ссылочных типов.

Когда вы вызываете "это" для ссылочного типа- вы получаете указатель, который живет в стеке, вы на самом деле не получаете сам объект.Указатель неявно разыменовывается обратно к объекту в куче, которая абстрагирует косвенное указание.Теперь, если вы сказали что-то вроде this = new MyReferenceType () , вы изменили указатель так, чтобы он указывал на другой объект кучи в текущей области действия - у вас есть not изменил сам исходный объект в куче, и никакие другие ссылки / указатели теперь не ссылаются на новый объект кучи.Весьма вероятно, что как только ваш мутированный указатель выйдет из области видимости - новый созданный вами объект кучи подвергнется сборке мусора.

Когда вы вызываете «this» для типа значения - вы получаете фактическийобъект, а не ссылка или указатель.Нет никакого косвенного обращения, так что вы можете перезаписать необработанные биты в этой ячейке памяти (это именно то, что делает конструктор по умолчанию).

1 голос
/ 06 апреля 2011

Просто предположение:

Каждый класс является ссылочным типом, означающим, что память выделяется в куче, и вызывающая сторона получает доступ к фактическим данным через указатель.Например:

Customer c1 = new Customer('CUSTID');   // "Customer" is a reference type 
Customer c2 = c1;   // "c1" and "c2" points to the same memory within the heap

Каждая структура - это тип значения, означающий, что память выделена в стеке, и вызывающая сторона имеет дело с фактическим экземпляром, а не со ссылкой на этот экземпляр.Например:

Customer c1 = new Customer('CUSTID');    // "Customer" is a value type 
Customer c2 = c1;   // New memory gets allocated for "c2" within the stack

Рассматривая ваш пример:

this = new Customer();

Выполнение следующей операции над структурой просто инициализирует ее нулевыми значениями:

mov eax,dword ptr [ebp-3Ch] ; Save pointer to "ebp-3Ch" in EAX register
xor edx,edx                 ; Clear EDX register
mov dword ptr [eax],edx     ; Write "zero" by address containing in EAX

НадеюсьЯ не знаю, почему это невозможно с ссылочными типами, но я предполагаю, что для этого потребуется пройти весь граф объекта, чтобы полностью «сбросить» его (что может быть непростой задачей).Я предполагаю, что это станет полезным в случае циклических ссылок.

Опять же, это только мои мысли, и я бы очень хотел, чтобы кто-то либо доказал, либо отвергнул (с объяснением, конечно) их.

...