Когда вы используете ключевое слово "this"?

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

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

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

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

public void SomeMethod()
{
    Vector vec = new Vector();
    double d = (vec * vec) - (this.radius * this.radius);
}

Ответ 1

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

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

Ответ 2

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

Серьезно.

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

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

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

Ответ 3

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

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;
    }

}

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

Ответ 4

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

Ответ 5

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

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

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

Пример:

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

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

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

Ответ 12

Здесь, когда я использую его:

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

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

Ответ 13

[С++]

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

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

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

Ответ 14

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

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

Я нашел это особенно полезной функцией.

Ответ 15

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

Например

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 добавляет немного очистителя.

Ответ 16

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

Ответ 17

Я получил привычку использовать его в Visual С++, так как это приведет к тому, что IntelliSense вызовет ключ " > ", и я ленив. (и склонны к опечаткам)

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

Ответ 18

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

Ответ 19

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

Ответ 20

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

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

Ответ 21

[С++]

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

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;
}

Ответ 22

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

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

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

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

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

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

Вот почему я использую this.

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

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

Ответ 23

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

Ответ 24

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

Удар CTRL + Space не помогает, поскольку он также включает типы; где - как "это". включает только членов.

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

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

Ответ 25

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

Ответ 26

@dicroce: "Существует штраф, связанный с ненужной многословностью" - какой штраф? Конечно, это не штраф за производительность. Может быть, исходный файл займет больше места на жестком диске? Или whaaat?

Ответ 27

1 - Идиома Common Java setter:

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

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

notifier.addListener(this);

Ответ 28

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

Ответ 29

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

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

Ответ 30

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

Вы можете использовать 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> (обратите внимание, что специализация базового шаблона может превратить его в совершенно разные типы, даже undefined типы), поэтому он просто предполагает, что это тип. На этом этапе независящий вызов f, который кажется просто естественным для программиста, является символом, который компилятор должен найти как член derived или в пространстве имен, который не встречается в примере, - и это будет жаловаться.

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

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