Коли ви використовуєте ключове слово "це"? [зачинено]


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

2
Я знайшов хороші приклади, коли вам справді потрібно this в MSDN. Перейдіть за цим посиланням ... ;-)
Метт

12
Якщо вам доведеться зрозуміти та оптимізувати чи переписати когось іншого, здебільшого погано написаного коду, ви були б раді мати thisчи будь-який інший класифікатор, щоб з простого вигляду ви дізналися область змінної (Особливо пропущені класифікатори класу для констант (той же пакет або ієрархія) або super/ baseкласифікатори). І використання часто використовуваного синтаксису _fooне здається для мене елегантним. Натискання _для інтелігенції більше забирає багато часу, ніж введення this. І навіщо взагалі турбуватися! З автоматичним збереженням функцій форматування затемнення не потрібно, _якщо ви забули класифікатор.
djmj

Прочитавши відповіді та коментарі нижче, а також прочитавши документацію MSDN: docs.microsoft.com/en-us/previous-versions/visualstudio/… про це ключове слово, яке не оновлювалось протягом 6 років, я б запропонував ніколи не використовувати це ключове слово. Це безглуздо. Не робіть однойменних параметрів, це заплутано і нерозумно. Навіщо ти це робив? Крім того, не передайте примірник у використанні цього , це також заплутано і нерозумно.
Юша

Відповіді:


218

У C # є кілька застосувань цього ключового слова.

  1. Щоб кваліфікувати членів, прихованих за подібною назвою
  2. Щоб об'єкт передав себе як параметр іншим методам
  3. Щоб об'єкт повертався з методу
  4. Декларувати індексатори
  5. Декларувати методи розширення
  6. Для передачі параметрів між конструкторами
  7. Для внутрішнього переназначення значення типу (структура) .
  8. Викликати метод розширення в поточному екземплярі
  9. Накинути себе на інший тип
  10. До ланцюжкових конструкторів, визначених в одному класі

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


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

Я не маю на увазі це звучати химерно, але це не має значення.

Серйозно.

Подивіться на важливі речі: ваш проект, ваш код, вашу роботу, особисте життя. Жоден із них не матиме успіху на тому, чи використовуєте Ви це слово для чи доступу до полів. Це ключове слово не допоможе вам доставити вчасно. Це не буде зменшувати помилки, це не матиме жодного помітного впливу на якість коду чи ремонтопридатність. Це не отримає вам підвищення, або дозволить вам менше часу проводити в офісі.

Це справді лише питання стилю. Якщо вам подобається "це", то використовуйте його. Якщо ні, то ні. Якщо вам це потрібно для отримання правильної семантики, тоді використовуйте її. Правда, кожен програміст має свій унікальний стиль програмування. Цей стиль відображає уявлення конкретного програміста про те, як повинен виглядати "найестетичніший код". За визначенням, будь-який інший програміст, який читає ваш код, матиме інший стиль програмування. Це означає, що завжди буде щось, що ви зробили, що іншому хлопцю не подобається, або зробили б інакше. У якийсь момент якийсь хлопець збирається прочитати ваш код і нарікати на щось.

Я б не хвилювався за це. Я би просто переконався, що код максимально естетично приємний відповідно до власних смаків. Якщо ви запитаєте 10 програмістів, як відформатувати код, ви отримаєте приблизно 15 різних думок. Краще зосередитись на тому, як розробляється код. Чи правильно абстрагуються речі? Я підбирав для речей значущі назви? Чи багато дублювання коду? Чи є способи я спростити речі? Правильне налаштування цих питань, я думаю, матиме найбільший позитивний вплив на ваш проект, ваш код, вашу роботу та ваше життя. Випадково це, ймовірно, також змусить іншого хлопця як мінімум нарікати. Якщо ваш код працює, його легко читати і добре враховувати, інший хлопець не збирається ретельно перевіряти, як ви ініціалізуєте поля. Він просто використовуватиме ваш код, дивуйтеся його величі,


35
thisКлючове слово семантично значущим. Дивіться коментар @ JasonBunting нижче. Ви плутаєте стилістичне надмірне використання thisз його фактичним призначенням. Ваше зауваження не просто легковажне, це неправильне!
Dan Barowy

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

}

Або як вказує Райан Фокс, коли вам потрібно передати це як параметр. (Локальні змінні мають перевагу перед змінними-членами)


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

Я не можу повірити, що всі люди, які кажуть, що використовувати це завжди, є "найкращою практикою".

Використовуйте "це", коли є двозначність, як у прикладі Корі або коли вам потрібно передавати об'єкт як параметр, як у прикладі Райана . Немає ніяких причин використовувати його інакше, оскільки можливість вирішити змінну на основі ланцюга області повинна бути достатньо зрозумілою, що кваліфікуючі змінні з нею повинні бути непотрібними.

EDIT: Документація C # на "це" вказує на ще одне використання, окрім двох, про які я згадував, для ключового слова "це" - для оголошення індексаторів

EDIT: @Juan: Так, я не бачу суперечливості в моїх заявах - є 3 випадки, коли я використовував би ключове слово "це" (як це зафіксовано в документації на C #), і це часи, коли вам це потрібно . Якщо "конструювати" це перед змінними в конструкторі, коли не відбувається затінення, це просто марно натискання клавіш, а марна трата мого часу під час його читання - це не приносить користі.


21
@ JasonBunting : Ви не можете щось робити іноді, а не деякі інші ... це заплутано ... Я сподіваюся, що я ніколи не працюю у вашому коді. Ви не завжди можете припустити, що людина, яка читає ваш код у майбутньому, зрозуміє, що ви писав, що вам потрібно , щоб бути якомога більш чіткими, і один з способів досягнення цього є бути послідовним
хуан

@juan, 10 років останнього. Ви все ще вважаєте, що використання "цього" є хорошою практикою? :)
Скотт Адамс

2
@ScottAdams я до сих пір вірю в послідовності і ясності, та
хуан

Що з визначенням сфери змінної (будь то локальна чи членська змінна), просто подивившись на неї? Чи не «це» виправдано для цієї мети? Або ви хочете сказати, що якщо ми пишемо менші методи, було б досить легко зрозуміти область змінної?
BornToCode

27

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


1
І ReSharper каже мені не користуватися цим. Вигляд плутанини, коли я одночасно використовую і StyleCop, і ReSharper :) Але я схиляюся до відповіді Coreys вище, щоб використовувати ключове слово "це" лише тоді, коли це абсолютно необхідно.
Гуннар

@Gunnar, є можливість відключити позбавлення від зайвого "цього". в R #
Вінгер Сендон

@EmperorAiman ​​- Так, я знаю. Моя думка полягала в тому, що ці два популярні інструменти форматування за замовчуванням пропонують дві різні речі і це може заплутати. "Бути чи не бути ..." :)
Гуннар

11

Будь-який час вам потрібно посилання на поточний об’єкт.

Особливо зручний сценарій - це коли ваш об'єкт викликає функцію і хоче передати себе в неї.

Приклад:

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

7

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


5

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


5

Ще одне дещо рідкісне використання цього ключового слова - це коли потрібно викликати явну реалізацію інтерфейсу з класу реалізації. Ось надуманий приклад:

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

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

4

Ось коли я його використовую:

  • Доступ до приватних методів з класу (для розмежування)
  • Передача поточного об'єкта іншому методу (або як об'єкт відправника, у разі події)
  • При створенні методів розширення: D

Я не використовую це для приватних полів, тому що я префіксую назви змінних приватних полів із підкресленням (_).


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Додає трохи освітлювач.


3

У відповіді Якуба Штурца його №5 про передачу даних між кондукторами, мабуть, можна було б використати невелике пояснення. Це в конструкторах, що перевантажують, і це єдиний випадок, коли використання thisобов'язкове. У наступному прикладі ми можемо викликати параметризований конструктор з конструктора без параметри з параметром за замовчуванням.

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

Я виявив це особливо корисною особливістю.


2

У мене з'явилася звичка використовувати його вільно у Visual C ++, оскільки це призведе до запуску IntelliSense, я натиснув клавішу '>', і я лінивий. (і схильний до друкарських помилок)

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


1

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


1

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


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 забруднюють ваше глобальне простір імен

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


1

"це". допомагає знайти членів класу "цей" з великою кількістю членів (зазвичай це пов'язано з глибоким ланцюгом спадкування).

Якщо натиснути CTRL + пробіл, це не допомагає, оскільки воно також включає типи; де-як 'це'. включає членів ТОЛЬКО.

Я, як правило, видаляю його після того, як у мене з’явилося те, що я був після: але це лише мій стиль, який пробивається.

З точки зору стилю, якщо ви самотній рейнджер - ви вирішите; якщо ви працюєте в компанії, дотримуйтесь політики компанії (подивіться на матеріали в контролі джерел і подивіться, що роблять інші люди). З точки зору використання його для кваліфікації членів, це ні правильно, ні неправильно. Єдина неправильна річ - непослідовність - це золоте правило стилю. Залиште інших, що збирають нитку. Витратьте свій час на обдумування реальних проблем кодування - і, очевидно, кодування - натомість.


1

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


1

Коли у вас багато розробників, що працюють на одній базі коду, вам потрібні деякі вказівки та правила щодо коду. Де я працюю, ми вирішили використати "це" на полях, властивостях та подіях.

Для мене є сенс зробити це так, це полегшує читання коду, коли ви розмежовуєте змінні класу та змінні методу.


0

Це залежить від стандарту кодування, над яким я працюю. Якщо ми використовуємо _ для позначення змінної екземпляра, то "цей" стає зайвим. Якщо ми не використовуємо _, то я схильний використовувати це для позначення змінної екземпляра.


0

Я використовую його для виклику Intellisense так само, як JohnMcG , але я повернусь і стерну "this->", коли закінчу . Я дотримуюся конвенції Майкрософт щодо префіксації змінних членів "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

Ви не повинні використовувати "це", якщо ви абсолютно не повинні.

Існує штраф, пов’язаний із зайвою багатослівністю. Ви повинні прагнути до коду, який є рівно стільки, скільки він повинен бути, і більше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.