Когда вы используете ключевое слово «это»? [закрыто]

249

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

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

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

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

public void SomeMethod()
{
    Vector vec = new Vector();
    double d = (vec * vec) - (this.radius * this.radius);
}
Magic Hat
источник
2
Я нашел хорошие примеры, когда вам действительно нужно this на MSDN. Пожалуйста, перейдите по этой ссылке ... ;-)
Мэтт
12
Если вам нужно понять и оптимизировать или переписать кого-то другого, в основном плохо написанный код, который вы были бы рады иметь, thisили любой другой классификатор, чтобы из простого взгляда вы знали область действия переменной (особенно пропущенные квалификаторы класса для констант (тот же пакет или иерархия) или super/ baseквалификаторы). И использование обычно используемого синтаксиса вроде _fooне кажется мне элегантным. Нажатие _на intellisense занимает больше времени, чем ввод this. И зачем вообще! С функциями автоматического форматирования eclipse нет необходимости, _если вы забыли классификатор.
djmj
После прочтения ответов и комментариев ниже, а также прочтения документации MSDN: docs.microsoft.com/en-us/previous-versions/visualstudio/… об этом ключевом слове, которое не обновлялось в течение 6 лет, я бы предложил никогда не использовать это ключевое слово. Это бессмысленно. Не делайте параметры одинаковыми, это сбивает с толку и глупо. Почему ты бы так поступил? Кроме того, не передавайте экземпляр в использовании этого , это также сбивает с толку и глупо.
Юша

Ответы:

218

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

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

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

Jakub Šturc
источник
49
8. Вызвать метод расширения для текущего экземпляра ( this.Foo();будет работать, но Foo()не будет)
Марк Гравелл
4
Также для приведения себя к другому типу, например, явно реализованный метод будет вызываться как ((ICollection<T>)this).Add(bla).
Nawfal
4
Чтобы связать конструкцию с другим конструктором, определенным в том же типе. public ClassName(...) : this(...),
Лассе В. Карлсен
1
@ И это никак не повлияет на производительность во время выполнения. Предполагая, что двусмысленности нет, выходные данные компилятора одинаковы, независимо от того, пишете ли вы, например, this.someField = someValueили someField = someValue. Это может повлиять на производительность компилятора, так как компилятор будет анализировать исходный код по-разному, но любая разница наверняка будет незначительной.
Фог
7
Вы можете избежать первой проблемы, получая доступ к полям через свойства, только если вы придерживаетесь стилевого соглашения, согласно которому свойства не могут иметь те же имена, что и параметры. Просто так получается, что распространенное соглашение о стиле C # отвечает этому требованию. Однако не все C # написаны в соответствии с этим соглашением. В свойствах как таковых нет ничего, что сделало бы thisключевое слово ненужным; вызываемый параметр конструктора xбудет скрывать вызываемый член, xнезависимо от того, является ли он полем, свойством или событием.
Фог
246

Я не хочу сказать, что это звучит странно, но это не имеет значения.

Шутки в сторону.

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

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

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

Скотт Вишневски
источник
35
thisКлючевое слово семантически значимым. Смотрите комментарий @ JasonBunting ниже. Вы путаете стилистическое злоупотребление thisс его фактическим назначением. Ваше замечание не просто легкомысленно, это неправильно!
Дэн Барови
12
Если у вас есть шанс, вы можете перечитать мой ответ. Я говорю об использовании его в тех случаях, когда это необходимо для правильной семантики. Вы также можете посмотреть на вопрос о происхождении. Это показывает использование в примерах, где это не семантически необходимо. Итак, я не уверен, что именно то, что я сказал, было «неправильно». Мой ответ, конечно, не легкомысленный.
Скотт Вишневски
9
Ты знаешь, как мой ответ звучит для меня? Между строк я читаю "Как ты смеешь задавать такой вопрос?" - Это действительно не конструктивно, на мой взгляд. Никто не знает всего - вот почему у нас есть Stackoverflow: помогать другим и получать помощь. Некоторые темы вы знаете, некоторые знают другие. Помогайте друг другу, не сражайтесь друг с другом. Пожалуйста, подумайте об этом.
Мэтт
9
Я не хочу показаться странным, но это пока один из худших ответов. Я не понимаю, насколько полезно сравнивать это с вашей работой или личной жизнью. То, что некоторые вещи менее важны, чем другие, не означает, что они не важны . Наличие последовательного стиля программирования не является неважным (прочитайте книгу о читаемости / удобстве сопровождения кода по вашему выбору).
aioobe
4
Я думаю, что вы, возможно, неправильно поняли мою точку зрения. Это не значит, что «иметь последовательный стиль» - это плохо. Я ничего не говорю об этом. Это вопрос о том, «должен ли мой стиль руководства поручить это». в качестве префикса для всех полевых доступов? " произвольно и капризно.
Скотт Вишневски
96

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

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

}

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

Corey
источник
6
В этом случае, почему бы просто не дать разные имена входным переменным конструктора?
wz366
54

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

Брэндон Вуд
источник
9
но если вы забудете использовать его когда-нибудь, они
запутаются
2
@surfen, которого можно избежать с помощью дополнительных проверок стилей, например, в Java вы можете использовать Checkstyle и запускать его после полной сборки (и на любом популярном итеративном / OO-языке будут подобные инструменты)
Maarten Bodewes
5
@ Surfen, как будто вы забыли это в неоднозначных случаях. Я могу разорвать любой аргумент, сказав «но если ты забудешь ...».
Асколейн
6
Кажется, что большинство людей никогда не читают, не оптимизируют и не переписывают чужой код! Квалификаторы - это экономия времени и мотивации! Без классификатора это похоже на магию, если вы видите произвольную строку кода. Таким образом, вы тратите все время, просто проверяя, откуда берутся эти переменные.
djmj
3
Я знаю, что это очень старый пост, но я не могу не прокомментировать иронию этого ответа (с которым я согласен). В «Джихаде против злой венгерской нотации» любой, кто осмелился префиксировать свои переменные-члены с помощью «m_», был быстро поставлен на позор, потому что различать переменные-члены было просто бесполезно или не нужно.
Майкл Дж.
38

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

Томас Оуэнс
источник
Я хочу как можно больше различать переменные класса, чтобы код был более понятным. Я использовал префикс m_ (переменная-член), например, личная строка m_name. Теперь я просто использую это, например, если у меня есть класс Test {private string a; public someMethod () {this.a = "foo"; }}
широкополосный
36

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

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

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

РЕДАКТИРОВАТЬ: @Juan: Да, я не вижу никаких противоречий в своих высказываниях - есть 3 случая, когда я использовал бы ключевое слово «this» (как описано в документации по C #), и это те моменты, когда вам это действительно нужно . Помещать «это» перед переменными в конструкторе, когда не происходит теневое копирование, - это просто трата нажатий клавиш и трата моего времени на чтение, это не дает никакой пользы.

Джейсон Бантинг
источник
21
@ JasonBunting : Вы не можете иногда делать что-то, а не что-то другое ... это сбивает с толку ... Я надеюсь, что я никогда не буду работать с вашим кодом. Вы не всегда можете предположить, что человек, который читает ваш код в будущем, поймет, что вы писал, что вам нужно , чтобы быть как можно более четкими, и один из способов достижения этого является быть последовательным
хуан
@juan, 10 лет спустя. Вы все еще думаете, что «это» - хорошая практика? :)
Скотт Адамс
2
@ScottAdams я до сих пор верю в последовательности и ясности, да
хуан
Как насчет определения области действия переменной (локальной или переменной-члена), просто взглянув на нее? Разве «это» не оправдано для этой цели? Или вы хотите сказать, что если мы напишем меньшие методы, было бы достаточно легко понять область действия переменной в любом случае?
BornToCode
27

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

Ян Нельсон
источник
1
И ReSharper говорит мне не использовать его. Что-то вроде путаницы, когда я использую и StyleCop, и ReSharper одновременно :) Но я склоняюсь к ответу Coreys, приведенному выше, использовать ключевое слово «this» только в случае крайней необходимости.
Гуннар
@Gunnar, есть возможность отключить избавление от лишнего «это». в R #
Вингер Сендон
@EmperorAiman ​​- Да, я знаю. Я хотел сказать, что эти два популярных инструмента форматирования по умолчанию предлагают две разные вещи, и это может сбивать с толку. «Быть ​​или не быть ...» :)
Гуннар
11

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

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

Пример:

void onChange()
{
    screen.draw(this);
}
Райан Фокс
источник
7

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

Philippe
источник
5

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

TheSmurf
источник
5

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

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

    object ICloneable.Clone()
    {
        throw new NotImplementedException();
    }
}
Пол Батум
источник
4

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

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

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

Vaibhav
источник
4

[C ++]

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

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

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

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

хуан
источник
3

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

Например

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

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

bobobobo
источник
3

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

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

Я обнаружил, что это особенно полезная функция в некоторых случаях.

Cyberherbalist
источник
2

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

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

JohnMcG
источник
1

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

JamesSugrue
источник
1

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

akmad
источник
1

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

boolean sameValue (SomeNum other) {
   return this.importantValue == other.importantValue;
} 
Пит Киркхэм
источник
1

[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;
}
укладчик
источник
1

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

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

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

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

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

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

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

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

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

paercebal
источник
1

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

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

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

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

Джонатан С Дикинсон
источник
1

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


источник
1

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

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

Лапа Бальцерзен
источник
0

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

Дэн Блэр
источник
0

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

Марк Рэнсом
источник
0

1 - идиома общего Java-сеттера:

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

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

notifier.addListener(this);
тонкий
источник
0

Есть одно использование, которое еще не было упомянуто в 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проверяется во втором раунде после подстановки параметра шаблона.

Дэвид Родригес - дрибеи
источник
-2

Вы не должны использовать «это», если вы абсолютно не должны.

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

dicroce
источник