Самостоятельное задание в С#
Я просматривал какой-то код, который я написал некоторое время назад, и понял, что сделал предположение о операторе присваивания в С#. Вот строка кода, о которой идет речь (она работает как ожидалось):
pointsChecked = pointsChecked ?? new List<Point>();
pointsChecked
- это список, указанный как параметр для рекурсивной функции. Это параметр по умолчанию со значением по умолчанию null
. То, что я хочу сделать, это инициализировать его один раз, а затем собрать коллекцию точек, которые я уже проверил, поэтому ее следует инициализировать только во время первой итерации.
Мое предположение заключалось в том, что С# защищен от самоопределения таким же образом, что С++ operator=
должен обеспечивать защиту при перегрузке (т.е. if(this == &rightHandSide) return *this;
). Однако я не смог найти какие-либо ресурсы, которые явно указывают, что это верно для С#.
Самый близкий пример, который я нашел, был этот вопрос о нулевом коалесцирующем операторе, где, как представляется, объект присваивается себе, если он не null
, В этом примере никто ничего не сказал о самоназвании, но я хочу быть уверенным, что это не плохая практика и что никаких отрицательных побочных эффектов нет.
Поиск в MSDN Я также обнаружил, что (перефразируя на основе моего понимания) значение с правой стороны копируется в значение с левой стороны и вернулся. Поэтому я снова не уверен, что плохо самонастраиваться.
Я знаю, что могу сделать следующее, чтобы быть более безопасным:
if(pointsChecked == null)
{
pointsChecked = new List<Point>();
}
Но я предпочел бы понять, что на самом деле происходит с самоназначением.
Ответы
Ответ 1
Назначение копирует ссылку на объект, а не содержимое объекта. Никакой настраиваемый код не выполняется как часть назначения переменной, содержащей ссылку на объект, когда-либо. Это также верно для структур.
В С++ назначение настраивается, в С# это не так.
Безопасно назначить одну и ту же ссылку на объект, уже содержащий его:
object someRef = new object();
someRef = someRef; //always does nothing
Это безопасно, как назначение любого другого значения:
int someVal = 123;
someVal = someVal; //always does nothing
Обратите внимание, что не существует общего способа клонирования/копирования объекта. Любое объяснение, основанное на наличии такого механизма, должно быть неправильным.
Самоназначение безопасно, потому что оно переводится в следующие приблизительные инструкции IL:
ldloc someRef
stloc someRef
Это четко обозначенная семантика. Сначала он загружает someRef
в стек, а затем сохраняет все, что находится в стеке, на someRef
.