Я просматривал некоторый код проекта с открытым исходным кодом недавно и нашел много случаев этого вида кода:
class SomeClass
{
private int SomeNumber = 42;
public ReturnValue UseSomeNumber(...)
{
int someNumberCopy = this.SomeNumber;
if (someNumberCopy > ...)
{
// ... do some work with someNumberCopy
}
else
{
// ... do something else with someNumberCopy
}
}
}
Там какая-либо реальная выгода к созданию копии переменной экземпляра?
Нет, если вы не хотите изменять значение SomeNumber и намереваетесь обновить someNumberCopy. Например, если бы вы собирались зациклить количество раз и собираетесь уменьшить someNumberCopy до нуля, чтобы отслеживать счетчик.
Я полагаю, что такое копирование переменной может защитить вас от какой-то внешней функции, изменяющей SomeNumber и изменяющей его без вашего ведома во время выполнения операции. Я потенциально мог бы это увидеть, если бы класс предполагалось использовать в многопоточном приложении. Может быть, не так, как я бы пошел, но это могло быть намерением автора.
Выполняет ли // ... некоторую работу с someNumberCopy
, что-то делает с someNumberCopy? Это меняет значение? Передается ли он методу, который может изменить значение?
Если нет, то нет, пользы нет.
Вы упустили некоторые важные детали .
Если у вас есть несколько потоков, обращающихся к SomeNumber и этот сценарий:
int someNumberCopy = this.SomeNumber;
if (someNumberCopy > x)
{
// do some work with someNumberCopy
// that relies on (someNumberCopy > x) == true
}
Тогда важно сделать копию.
Единственное преимущество, которое я вижу, - наличие "версии только для чтения" переменной только для этого метода
Было бы полезно, если бы this.SomeNumber
мог быть изменен другим потоком, но для продолжительности этого метода жизненно важно, чтобы someNumberCopy
не может быть изменен (он может не синхронизироваться с SomeNumber
), тогда это может быть жизнеспособным, иначе я не вижу для этого причины.
Возможно, это часть многопоточной программы. Хотя этот код не является потокобезопасным, он гарантирует, что после того, как переменная копирования будет назначена, она не будет изменена другими потоками, и весь код функции после этого будет выполняться согласованно.
Подобный код с событиями становится критичным в многопоточной среде:
MyEvent e = this.myEvent; if ( e != null ) { e(); }
Здесь, без создания локальной копии, можно получить исключение нулевого указателя, если событие становится нулевым после проверки на ноль и до вызова.