Когда вы используете ключевое слово “this”?[закрыто]

StackOverflow https://stackoverflow.com/questions/23250

  •  09-06-2019
  •  | 
  •  

Вопрос

Мне было любопытно узнать, как другие люди используют это ключевое слово.Я обычно использую его в конструкторах, но я также могу использовать его во всем классе в других методах.Несколько примеров:

В конструкторе:

public Light(Vector v)
{
    this.dir = new Vector(v);
}

В другом месте

public void SomeMethod()
{
    Vector vec = new Vector();
    double d = (vec * vec) - (this.radius * this.radius);
}
Это было полезно?

Решение

Существует несколько способов использования это ключевое слово в C #.

  1. Чтобы квалифицировать участников, скрытых под похожими именами
  2. Чтобы объект передавал себя в качестве параметра другим методам
  3. Чтобы объект возвращал сам себя из метода
  4. Объявлять индексаторы
  5. Объявлять методы расширения
  6. Для передачи параметров между конструкторами
  7. Для внутреннего переназначения значения типа (struct) value.
  8. Чтобы вызвать метод расширения в текущем экземпляре
  9. Привести себя к другому типу
  10. Для связывания конструкторов, определенных в одном классе

Вы можете избежать первого использования, не имея в области видимости переменных-членов и локальных переменных с одинаковыми именами, например, следуя общим соглашениям об именовании и используя свойства (в случае Pascal) вместо полей (в случае camel), чтобы избежать столкновения с локальными переменными (также в случае camel).В C # 3.0 поля могут быть легко преобразованы в свойства с помощью автоматически реализованные свойства.

Другие советы

Я не хочу, чтобы это прозвучало язвительно, но это не имеет значения.

Серьезно.

Посмотрите на то, что действительно важно:ваш проект, ваш код, ваша работа, ваша личная жизнь.Успех ни одного из них не будет зависеть от того, используете ли вы ключевое слово "this" для получения доступа к полям.Ключевое слово this не поможет вам выполнить доставку вовремя.Это не уменьшит количество ошибок, не окажет сколько-нибудь заметного влияния на качество кода или ремонтопригодность.Это не принесет вам прибавки к зарплате и не позволит проводить меньше времени в офисе.

На самом деле это просто проблема стиля.Если вам нравится "это", то используйте его.Если ты этого не сделаешь, то и не делай.Если вам это нужно для получения правильной семантики, то используйте его.Правда в том, что у каждого программиста есть свой собственный уникальный стиль программирования.Этот стиль отражает представления конкретного программиста о том, как должен выглядеть "наиболее эстетичный код".По определению, у любого другого программиста, который читает ваш код, будет другой стиль программирования.Это означает, что всегда будет что-то, что вы сделали, что другому парню не понравится, или он поступил бы по-другому.В какой-то момент какой-нибудь парень прочитает ваш код и будет о чем-то ворчать.

Я бы не стал беспокоиться из-за этого.Я бы просто позаботился о том, чтобы код был максимально эстетичным в соответствии с вашими собственными вкусами.Если вы спросите 10 программистов, как форматировать код, вы получите около 15 различных мнений.Лучше всего сосредоточиться на том, как учитывается код.Правильно ли абстрагируются вещи?Подбирал ли я осмысленные названия для вещей?Много ли дублируется кода?Есть ли способы, которыми я могу все упростить?Я думаю, что правильное выполнение этих задач окажет наибольшее положительное влияние на ваш проект, ваш код, вашу работу и вашу жизнь.По случайному совпадению, это, вероятно, также заставит другого парня ворчать меньше всего.Если ваш код работает, легко читается и хорошо проанализирован, другой пользователь не будет тщательно изучать, как вы инициализируете поля.Он просто воспользуется вашим кодом, поразится его величию, а затем перейдет к чему-то другому.

Я использую его только тогда, когда это абсолютно необходимо, т.е. когда другая переменная затеняет другую.Например, здесь:

class Vector3
{
    float x;
    float y;
    float z;

    public Vector3(float x, float y, float z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

}

Или, как указывает Райан Фокс, когда вам нужно передать это в качестве параметра.(Локальные переменные имеют приоритет над переменными-членами)

Лично я стараюсь всегда использовать это при обращении к переменным-членам.Это помогает прояснить код и сделать его более читабельным.Даже если двусмысленности нет, кто-то, читающий мой код в первый раз, не знает этого, но если он увидит это при постоянном использовании они будут знать, просматривают ли они переменную-член или нет.

Я использую его каждый раз, когда ссылаюсь на переменную экземпляра, даже если мне это не нужно.Я думаю, это делает код более понятным.

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

Используйте "это", когда есть двусмысленность, как в Пример Кори или когда вам нужно передать объект в качестве параметра, как в Пример Райана.Нет причин использовать его иначе, потому что возможность разрешить переменную на основе цепочки областей видимости должна быть достаточно ясной, чтобы не было необходимости уточнять переменные с ее помощью.

Редактировать:Документация C # по "this" указывает на еще одно использование, помимо двух упомянутых мной, для ключевого слова "this" - для объявления индексаторов

Редактировать:@Хуан:Да, я не вижу никакой несогласованности в своих заявлениях - есть 3 случая, когда я использовал бы ключевое слово "this" (как задокументировано в документации C #), и это те случаи, когда вы на самом деле потребность IT.Вставлять "this" перед переменными в конструкторе, когда нет затенения, - это просто пустая трата нажатий клавиш и моего времени при чтении, это не приносит никакой пользы.

Я использую его всякий раз, когда Стилкоп велит мне это сделать. Стилкоп нужно повиноваться.Ах да.

В любое время, когда вам нужна ссылка на текущий объект.

Один из особенно удобных сценариев - это когда ваш объект вызывает функцию и хочет передать себя в нее.

Пример:

void onChange()
{
    screen.draw(this);
}

Я также склонен использовать его везде, просто чтобы убедиться, что ясно, что мы имеем дело с членами экземпляра.

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

Другое несколько редкое использование ключевого слова this - это когда вам нужно вызвать явную реализацию интерфейса из реализующего класса.Вот надуманный пример:

class Example : ICloneable
{
    private void CallClone()
    {
        object clone = ((ICloneable)this).Clone();
    }

    object ICloneable.Clone()
    {
        throw new NotImplementedException();
    }
}

Вот когда я им пользуюсь:

  • Доступ к закрытым методам изнутри класса (для дифференциации)
  • Передача текущего объекта другому методу (или в качестве объекта-отправителя, в случае события)
  • При создании методов расширения:D

Я не использую это для закрытых полей, потому что я добавляю к именам переменных закрытых полей символ подчеркивания (_).

[C++]

Я согласен с командой "используй это, когда понадобится".Излишне украшать код с помощью это это не очень хорошая идея, потому что компилятор не предупредит вас, когда вы забудете это сделать.Это создает потенциальную путаницу для людей, ожидающих это всегда быть рядом, т.е.им придется подумай об этом.

Итак, когда бы вы им воспользовались?Я только что просмотрел некоторый случайный код и нашел эти примеры (я не выношу суждения о том, являются ли они хорошо что нужно сделать или как-то иначе):

  • Передача "себя" функции.
  • Присваивание "себя" указателю или что-то в этом роде.
  • Литье, т.е.приведение вверх / вниз (безопасное или иное), устранение постоянства и т.д.
  • Компилятор принудительно устранил неоднозначность.

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

Например

class AABB
{
  // ... members
  bool intersects( AABB other )
  {
    return other.left() < this->right() &&
           this->left() < other.right() &&

           // +y increases going down
           other.top() < this->bottom() &&
           this->top() < other.bottom() ;
  }
} ;

(против)

class AABB
{
  bool intersects( AABB other )
  {
    return other.left() < right() &&
           left() < other.right() &&

           // +y increases going down
           other.top() < bottom() &&
           top() < other.bottom() ;
  }
} ;

С первого взгляда, что делает AABB right() ссылаться на?Тот Самый this добавляет немного осветлителя.

В ответе Якуба Штурца № 5 о передаче данных между конструкторами, вероятно, не помешало бы небольшое объяснение.Это связано с перегрузкой конструкторов и является единственным случаем, когда использование this является обязательным.В следующем примере мы можем вызвать параметризованный конструктор из конструктора без параметров с параметром по умолчанию.

class MyClass {
    private int _x
    public MyClass() : this(5) {}
    public MyClass(int v) { _x = v;}
}

Иногда я нахожу эту функцию особенно полезной.

Вы всегда должны использовать его, я использую его для уточнения личных полей и параметров (поскольку в наших соглашениях об именовании указано, что мы не используем префиксы для имен членов и параметров (и они основаны на информации, найденной в Интернете, поэтому я считаю это лучшей практикой))

У меня вошло в привычку широко использовать его в Visual C ++, поскольку это привело бы к запуску IntelliSense, я нажал клавишу ">", а мне лень.(и склонен к опечаткам)

Но я продолжал использовать его, так как мне было удобно видеть, что я вызываю функцию-член, а не глобальную функцию.

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

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

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

boolean sameValue (SomeNum other) {
   return this.importantValue == other.importantValue;
} 

[C++]

это используется в операторе присваивания, где большую часть времени вам приходится проверять и предотвращать странные (непреднамеренные, опасные или просто пустую трату времени для программы) вещи, такие как:

A a;
a = a;

Ваш оператор присваивания будет записан:

A& A::operator=(const A& a) {
    if (this == &a) return *this;

    // we know both sides of the = operator are different, do something...

    return *this;
}

this в компиляторе C ++

Компилятор C ++ автоматически выполнит поиск символа, если не найдет его немедленно.Иногда, в большинстве случаев, это хорошо:

  • используя метод материнского класса, если вы не перегрузили его в дочернем классе.
  • перевод значения одного типа в другой тип

Но иногда, Вы просто не хотите, чтобы компилятор угадал.Вы хотите, чтобы компилятор выбрал правильный символ, а не другой.

Для меня, это когда внутри метода я хочу получить доступ к методу-члену или переменной-члену.Я просто не хочу, чтобы какой-то случайный символ был выбран только потому, что я написал printf вместо того, чтобы print. this->printf не стал бы компилироваться.

Дело в том, что с устаревшими библиотеками C (§), устаревшим кодом, написанным много лет назад (§§), или что бы там ни происходило на языке, где копирование / вставка является устаревшей, но все еще активной функцией, иногда отличной идеей является указание компилятору не играть в остроумие.

Вот причины, по которым я использую this.

(§) для меня это все еще загадка, но теперь я задаюсь вопросом, не является ли тот факт, что вы включили заголовок <windows.h> в свой исходный код, причиной того, что все символы устаревших библиотек C будут загрязнять ваше глобальное пространство имен

(§§) понимание того, что "вам нужно включить заголовок, но включение этого заголовка нарушит ваш код, потому что он использует какой-то тупой макрос с общим именем", является одним из таких русская рулетка моменты из жизни программиста

'this.' помогает найти участников в "этом" классе с большим количеством членов (обычно из-за глубокой цепочки наследования).

Нажатие CTRL + Пробел не помогает с этим, потому что оно также включает типы;где-как "это". включает ТОЛЬКО участников.

Обычно я удаляю его, как только получаю то, что мне было нужно:но это просто прорыв моего стиля.

С точки зрения стиля, если вы рейнджер-одиночка - решать вам;если вы работаете в компании, придерживайтесь политики компании (посмотрите на материал в системе управления версиями и посмотрите, что делают другие люди).С точки зрения использования его для отбора участников, ни то, ни другое не является правильным или неправильным.Единственная неправильная вещь - это непоследовательность - это золотое правило стиля.Оставь придираться к другим.Вместо этого потратьте свое время на обдумывание реальных проблем кодирования - и, очевидно, на само кодирование - .

Это зависит от стандарта кодирования, в соответствии с которым я работаю.Если мы используем _ для обозначения переменной экземпляра, то "this" становится избыточным.Если мы не используем _, то я обычно использую это для обозначения переменной экземпляра.

Я использую его для вызова Intellisense точно так же , как JohnMcG, но я вернусь и сотру "это->", когда закончу.Я следую соглашению Microsoft о префиксе переменных-членов с помощью "m_", поэтому оставлять это в качестве документации было бы просто излишним.

1 - Распространенная идиома Java-сеттера:

 public void setFoo(int foo) {
     this.foo = foo;
 }

2 - При вызове функции с этим объектом в качестве параметра

notifier.addListener(this);

Я использую его каждый раз, когда могу.Я считаю, что это делает код более читаемым, а более читаемый код означает меньше ошибок и большую ремонтопригодность.

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

На мой взгляд, имеет смысл сделать это так, это облегчает чтение кода, когда вы проводите различие между переменными класса и переменными метода.

Существует одно применение, которое еще не упоминалось в C ++, и оно заключается не в том, чтобы ссылаться на собственный объект или устранять неоднозначность члена из полученной переменной.

Вы можете использовать this преобразование независимого имени в имя, зависящее от аргумента, внутри классов шаблонов, которые наследуются от других шаблонов.

template <typename T>
struct base {
   void f() {}
};

template <typename T>
struct derived : public base<T>
{
   void test() {
      //f(); // [1] error
      base<T>::f(); // quite verbose if there is more than one argument, but valid
      this->f(); // f is now an argument dependent symbol
   }
}

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

На этом этапе, фактически не заменяя тип, компилятор почти не имеет информации о том, что base<T> может быть (обратите внимание, что специализация базового шаблона может превратить его в совершенно разные типы, даже неопределенные типы), поэтому он просто предполагает, что это тип.На этом этапе независимый вызов f это кажется программисту вполне естественным символом, который компилятор должен найти как член derived или во вложенных пространствах имен - чего не происходит в приведенном примере - и он будет жаловаться.

Решение заключается в превращении независимого имени f в зависимое имя.Это можно сделать несколькими способами, явно указав тип, в котором это реализовано (base<T>::f --добавление base<T> делает символ зависимым от T и компилятор просто предположит, что он будет существовать, и откладывает фактическую проверку на второй проход, после замены аргумента.

Второй способ, гораздо более простой, если вы наследуете шаблоны, которые имеют более одного аргумента или длинных имен, - это просто добавление this-> перед символом.Поскольку класс шаблона, который вы реализуете, зависит от аргумента (он наследуется от base<T>) this-> зависит от аргумента, и мы получаем тот же результат: this->f проверяется во втором раунде, после замены параметра шаблона.

Вы не должны использовать "это" без крайней необходимости.

Существует наказание, связанное с излишним многословием.Вы должны стремиться к тому, чтобы код был ровно такой длины, какой ему нужно, и не длиннее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top