Изменение переменной 'this' типов значений

По-видимому, вы можете изменить значение this из любой точки вашей структуры (но не в классах):

struct Point
{
    public Point(int x, int y)
    {
        this = new Point();
        X = x; Y = y;
    }
    int X; int Y;
}

Я не видел этого раньше и никогда не нуждался в нем. Зачем это когда-либо хотеть? Эрик Липперт напоминает нам, что функция должна быть оправдана для реализации. Какой большой пример использования может это оправдать? Существуют ли какие-либо сценарии, где это бесценно? Я не смог найти на нем никакой документации 1.

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

public Point(int x, int y)
    : this()
{
    X = x; Y = y;
}

Я нашел эту функцию в примере в Jeffrey Richter CLR через С# 4-е издание.
1) По-видимому, он находится в спецификации С#.

Ответ 1

Хороший вопрос!

Типы значений по определению копируются по значению. Если this на самом деле не является псевдонимом для места хранения, тогда конструктор будет инициализировать копию, а не инициализировать переменную, которую вы собираетесь инициализировать. Это сделало бы конструктора менее полезным! И аналогично для методов; да, изменчивые структуры злы, но если вы собираетесь снова создать переменную структуру, this должна быть переменной, которая мутируется, а не копией ее значения.

Поведение, которое вы описываете, является логическим следствием этого дизайнерского решения: поскольку this псевдонизирует переменную, вы можете назначить ему такую ​​же, как вы можете назначить любой другой переменной.

Несколько странно назначать непосредственно this, как это, вместо назначения его полям. Еще более странно назначать непосредственно this, а затем перезаписывать 100% этого задания!

Альтернативный дизайн, который позволил бы сделать this псевдоним хранилища приемника, должен был выделить this из кратковременного пула хранения, инициализировать его в ctor и затем вернуть его по значению. Нижняя сторона этого подхода заключается в том, что оптимизация копирования исключений практически невозможна, и это делает ctors и методы странно непоследовательными.

Ответ 2

Кроме того, я не мог найти на нем никакой документации.

Вы пытались найти в спецификации С#? Поскольку я могу найти на нем документацию (7.6.7):

  • Когда this используется в первичном выражении внутри конструктора экземпляра структуры, он классифицируется как переменная. Тип переменной - тип экземпляра (§10.3.1) структуры, в которой происходит использование, и переменная представляет построенную структуру. Переменная this конструктора экземпляра структуры ведет себя точно так же, как параметр out типа struct - в частности, это означает, что переменная должна быть определенно назначена в каждом пути выполнения конструктора экземпляра.

  • Когда this используется в первичном выражении внутри метода экземпляра или экземпляра экземпляра структуры, он классифицируется как переменная. Тип переменной - тип экземпляра (§10.3.1) структуры, в которой происходит использование.

    • Если метод или аксессор не является итератором (§10.14), переменная this представляет структуру, для которой был вызван метод или accessor, и ведет себя точно так же, как параметр ref типа struct.
    • Если метод или аксессор - это итератор, переменная this представляет собой копию структуры, для которой был вызван метод или аксессуар, и ведет себя точно так же, как параметр значения для типа структуры.

Что касается прецедента для него, я не могу сразу думать о многих - о единственном, что у меня есть, - если значения, которые вы хотите назначить в конструкторе, дорого вычислять, и у вас есть кешированное значение, которое вы хотите скопировать в this, это может быть удобно.

Ответ 3

Место хранения типа значения в агрегировании мест хранения, включающих публичные и частные поля этого типа. Передавая тип значения, обычный параметр (значение) будет физически и семантически передавать содержимое всех его полей. Передача типа значения в качестве параметра ref семантически передает содержимое всех его полей, хотя для их передачи используется один "byref".

Вызов метода в структуре эквивалентен передаче структуры (и, следовательно, всех ее полей) в качестве параметра ref, за исключением одной морщинки: обычно ни С#, ни vb.net не допускают значение только для чтения передается как параметр ref. Однако оба метода позволят использовать методы struct для значений только для чтения или временных значений. Они делают это, создавая копию всей структуры (и, следовательно, всех ее полей), а затем передавая эту копию как параметр ref.

Из-за этого поведения некоторые люди называют изменчивые структуры "злыми", но единственное, что зло - это тот факт, что ни С#, ни vb.net не определяют какой-либо атрибут, чтобы указать, должен ли элемент или свойство структуры быть invokable для вещей, которые не может быть передано непосредственно ref.