Підкреслювати або не підкреслювати, це питання


130

Чи є проблеми з нефіксацією приватних полів з підкресленням у C #, якщо двійкова версія буде використовуватися іншими мовами рамки? Наприклад, оскільки C # відрізняється від регістру, ви можете назвати поле "foo" та загальнодоступну власність "Foo", і воно прекрасно працює.

Буде чи це мати якийсь - або ефект на регістронезавісімого мовою, як VB.NET, коли буде яка - або CLS-відповідність (або іншими) проблемами , якщо імена помітні тільки кожух?


18
Суть префікса підкреслення, BTW, не в тому, щоб розібратися зі справами. Це вміти легко та візуально розказувати поля та місцеві жителі, читаючи код. Я буду використовувати його в C # і VB так.
Ніл Хьюїтт

2
@NeilHewitt: Добре, це також запобігає конфліктуванню параметрів функції з змінними-членами, які вимагають попередньо передбачити кожен із них this, який затримує. EDIT: Я щойно відповів на чотирирічний коментар ...
Ed S.

Тільки для ясності офіційний стандарт _camelCase( читається тільки на
Кріс Марісіч

Я віддаю перевагу _camelCase для приватних магазинів. тобто приватне подане, що містить дані, призначені та доступні через власність. Мені не подобаються автоматичні властивості, оскільки вони не можуть бути ініціалізовані до відомого значення у визначенні класу, і якщо я хочу побічний ефект у сеттері, мені потрібна явно оголошена резервна сховища. На жаль, це виправляється, коли я використовую ^ R ^ E в редакторі c #, тому мені доводиться додавати його знову ... щоразу.
TomXP411

Відповіді:


46

Це не буде мати НЕ ефект.

Частина рекомендацій щодо написання бібліотек, сумісних з CLS, полягає в тому, щоб НЕ було двох публічних / захищених об'єктів, які відрізняються лише залежно від конкретного випадку, наприклад, ви НЕ повинні мати

public void foo() {...}

і

public void Foo() {...}

те, що ви описуєте, не є проблемою, оскільки приватний елемент недоступний для користувача бібліотеки


1
Незважаючи на те, що ніякого ефекту не буде, це все-таки є умовою, з якою мені буде незручно - оскільки це рецепт плутанини, якщо вони різняться лише у випадку. Це занадто просто неправильно читати чи неправильно вводити, якщо єдиною різницею є початковий капітал.
ChrisA

2
PS Особисто я не підкреслюю C #. Для мене це особисті переваги, а не релігійна віра
Бінарний страшник

1
Я зробив обидва способи, і хотів скласти свою думку,
повсякчас

46
Я використовую підкреслення. Їх легше відрізнити від аргументів та локальних змінних.
Рінат Абдуллін

4
Я використовую _ лише для приватних полів, однак я майже ніколи не маю приватних полів через 3,5 власності авто. Як правило, єдиний раз, коли я маю приватне поле, це якщо я впроваджую ледачу завантаження на непомітні типи.
Кріс Марісіч

278

ВАЖЛИВО ОНОВЛЕННЯ (12 квітня 2016 р.):

Ми звернули увагу на те, що внутрішній стандарт команди .NET CoreFX наполягає на використанні підкреслювальної позначення, не даючи жодної розуміння того, чому. Однак , якщо ми уважно подивимося на правила # 3 стає очевидним , що існує система _, t_, s_префіксів, передбачає , чому _був обраний в першу чергу.

  1. Ми використовуємо _camelCaseдля внутрішніх і приватних полів і використовуємо лише для читання лише там, де це можливо. Поля примірника префікса з _, статичні поля з s_і потокові статичні поля з t_. При використанні в статичних полях readonlyслід надходити static(тобто static readonlyні readonly static).
  2. Ми уникаємо, this.якщо абсолютно не потрібно.

Отже, якщо ви просто схожі на команду .NET CoreFX, яка працює над критичним, багатопотоковим, системним кодом на рівні продуктивності , то вам НАДІЙНО ЗАПРОШЕНО :

  • дотримуватися своїх стандартів кодування та
  • використовувати позначення підкреслення та
  • більше не читайте цю відповідь

В іншому випадку читайте далі ...

ОРИГІНАЛЬНИЙ ВІДПОВІДЬ:

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

Підкреслення-позначення

  • пропонує використовувати префікс "_" у назвах приватних полів
  • він також говорить, що ніколи не слід використовувати "це", якщо це абсолютно не потрібно

Це-позначення

  • пропонує вам просто завжди використовувати "це". для доступу до будь-якого члена примірника

Чому це позначення існує?

Тому що це ти

  • скажіть один від одного параметр від поля, коли вони мають спільне ім’я
  • переконайтеся, що ви працюєте в контексті поточного примірника

Приклад

public class Demo
{
   private String name;
   public Demo(String name) {
       this.name = name;
   }
}

Чому існує підкреслення-позначення?

Деяким людям не подобається вводити "це", але вони все ще потребують способу розрізнити поле та параметр, тому вони погодилися використовувати "_" перед полем

Приклад

public class Demo
{
   private String _name;
   public Demo(String name) {
      _name = name;
   }
}

Можна подумати, що це лише питання особистого смаку, і обидва способи однаково хороші / погані. Однак є певні аспекти, де ця нотація перемагає підкреслення:

Чіткість

  • підкреслення символів захаращує імена
  • ця нотація зберігає імена недоторканими

Пізнавальне навантаження

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

  • це позначення є послідовним, вам не потрібно думати, ви просто завжди використовуєте "це" для позначення будь-якого учасника

ОНОВЛЕННЯ: як було зазначено, наступне не є перевагою

Технічне обслуговування

  • Підкреслення нотації вимагає від вас _уважного під час рефакторингу, скажімо, перетворення поля у властивість (видалити _) або навпаки (додати _)

  • ця нотація не має такої проблеми

Автозавершення

Коли вам потрібно переглянути список членів екземпляра:

  • Підкреслення нотації не дуже допоможе вам, тому що при введенні "_" спливаюче вікно автозаповнення показує вам приватні поля та всі типи, доступні з пов'язаних збірок, змішаних з рештою членів екземпляра
  • ця нотація дає вам чітку відповідь, набравши "це", все, що ви бачите, - це список членів і нічого іншого

Неоднозначність

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

  • Підкреслення нотацій неоднозначне: коли ви бачите Something.SomethingElse, ви не можете сказати, чи щось є клас, а SomethingElse - його статична властивість ... чи, можливо, щось є поточним властивістю екземпляра, яке має свою властивість SomethingElse

  • ця нотація зрозуміла: коли ви бачите Something.SomethingElse, це може означати лише клас зі статичною властивістю і коли ви бачите це.Something.SomethingElse, ви знаєте, що щось є членом, а SomethingElse - його властивістю

Методи розширення

Не можна використовувати методи розширень у самому екземплярі без використання "цього".

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

Підтримка Visual Studio

  • Підкреслення нотацій не має вбудованої підтримки у Visual Studio
  • ця нотація підтримується Visual Studio природно:

    1. "Це". Кваліфікація . Віддайте перевагу всім нестатичним полям, які використовуються в нестатичних методах, на this.C #

Офіційні рекомендації

Існує багато офіційних вказівок, які чітко говорять про те, що "не використовуйте підкреслення", особливо в C #


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

5
Не походить від C ++, тому що в C ++ резерви ідентифікаторів починаються з підкреслення для мови та стандартних звичаїв бібліотеки.
Роб Г

7
Чому ви розрізняєте критичну ефективність, багатопоточність, код рівня системи та інший код? Як за допомогою _camelCaseдопомогти мені, якщо мій код критичний для продуктивності / код системного рівня?
BornToCode

6
Використання підкреслення не має нічого спільного з написанням критичного, багатопотокового або системного коду на рівні ефективності. Це важливість послідовності, а команда CoreFX - це лише команда, яка погодилася на конкретну конвенцію. Це чудова відповідь, підкріплений дуже приємним аналізом порівняння конвенцій про іменування, але я вважаю, що додана частина говорить "підкреслення краще, тому що команда CoreFX так говорить" дійсно знижує її якість.
Şafak Gür

5
Моя проблема полягає в тому, що я розумію логічні умовиводи. en.wikipedia.org/wiki/Інференція Але ей, я розумію, це не для всіх.
user603563

67

Взяте з файлу довідки Microsoft StyleCop:

TypeName: FieldNamesMustNotBeginWithUnderscore

CheckId: SA1309

Причина: Назва поля в C # починається з підкреслення.

Опис правила:

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

За замовчуванням StyleCop забороняє використовувати підкреслення, m_ тощо для позначення полів місцевого класу на користь "цього". префікс. Перевага використання "цього". полягає в тому, що він застосовується однаково до всіх типів елементів, включаючи методи, властивості тощо, а не лише поля, завдяки чому всі виклики членів класу миттєво впізнаються, незалежно від того, який редактор використовується для перегляду коду. Ще одна перевага полягає в тому, що це створює швидку, впізнавану диференціацію між елементами екземпляра та статичними членами, що не буде префіксом.

Якщо ім'я поля чи змінної призначене для узгодження імені елемента, пов’язаного з Win32 або COM, і, таким чином, потрібно починати з підкреслення, помістіть поле або змінну в спеціальний клас NativeMethods. Клас NativeMethods - це будь-який клас, який містить ім'я, що закінчується на NativeMethods, і призначений як заповнювач для обгортки Win32 або COM. StyleCop проігнорує це порушення, якщо елемент розміщений у класі NativeMethods.

Інший опис правил вказує на те, що кращою практикою, крім вищезазначеного, є запуск приватних полів з малих літер, а публічних з великих літер.

Редагувати: У подальшому сторінка проекту StyleCop розміщена тут: https://github.com/DotNetAnalyzers/StyleCopAnalyzers . Читання файлів довідки дає багато розуміння того, чому вони пропонують різні стилістичні правила.


7
Це здебільшого "найкращі практики". Як зазначається в правилі, префікс "це" може бути застосований до будь-якого нестатичного члена, тоді як префіксація з будь-яким іншим може не застосовуватися через правила синтаксису мови. Ключове слово "це" робить передбачуване призначення тривіально зрозумілим.
Скотт Дорман

5
Я також віддаю перевагу мовному вирішенню проблеми ("це") через штучні способи її подолання.
галактор

10
Також є правило в тому ж програмному забезпеченні, яке говорить, що у вас не повинно бути двох полів, що відрізняються лише у випадку. То що ви робите із захищеною змінною, охопленою громадською власністю?
Річка Ліліт

5
Моя єдина проблема з питанням "без підкреслення" полягає в тому, що при програмуванні на (веб) формі або подібній формі використання просто "цього" мені зовсім не допомагає відфільтруватися до тих приватних полів, які я визначив, а натомість просто дає мені гігантський перелік восьми мільйонів інших властивостей, що входять до цього об'єкта.

14
Схоже, StyleCop каже, що, якщо я послідовно використовую, thisколи я посилаюся на будь-якого члена класу, я можу знайти всі дзвінки до всіх членів класу просто шляхом пошуку this. Я не можу з цим посперечатися, але я також не можу придумати час, коли мені це потрібно було зробити. Останнє, що я хочу зробити, - це додати коду до кодування та засмітити мій код this(який майже є угорським) за майже ніякий практичний прибуток. Справа в тому, що якщо я дивлюся на рядок коду, все, що починається з великої літери або підкреслення, є членом класу, будь-який нижній регістр - локальний.
devuxer

27

Оскільки ми говоримо про приватне поле, це не впливає на користувача вашого класу.

Але я рекомендую використовувати підкреслення для приватного поля, оскільки це може полегшити розуміння коду, наприклад:

private int foo;
public void SetFoo(int foo)
{
  // you have to prefix the private field with "this."
  this.foo = foo;

  // imagine there's lots of code here,
  // so you can't see the method signature



  // when reading the following code, you can't be sure what foo is
  // is it a private field, or a method-argument (or a local variable)??
  if (foo == x)
  {
    ..
  }
}

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


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

9
Для мене підкреслення є свого роду скороченням "цього".
M4N

2
У R # порада не називати параметр foo. Чому б не назвати це значенням, оскільки ви знаєте, що він буде використовуватися для встановлення Foo?
подумайте перед тим, як кодувати

17
@Martin: Проблема з підкресленням як скороченням "цього" полягає в тому, що він не обов'язково може бути застосований до всіх членів класу, тоді як "це" може. Я думаю, що код читає набагато простіше / чистіше з ключовим словом "це". У вашому прикладі, якщо (foo == x) завжди буде посилатися на параметр foo.
Скотт Дорман

3
@TheCodeJunkie: Це багато зайвих символів у вашій кодовій базі.
Ред С.

15

Після роботи в середовищі, яке склало дуже специфічні та безглузді правила стилю з того часу, я продовжував створювати свій власний стиль. Це один тип, який я багато перевертав туди-сюди. Я, нарешті, вирішив, що приватні поля завжди будуть _field, локальні змінні ніколи не матимуть _ і будуть малі регістри, імена змінних для елементів керування будуть слабко слідувати угорському позначенню, а параметри, як правило, будуть camelCase.

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

6-річне оновлення: я аналізував внутрішні дані Dictionary<TKey,T>конкретного використання паралельного доступу та неправильно читав приватне поле як локальну змінну. Приватні поля безумовно не повинні бути такою ж умовою іменування, як локальні змінні. Якби було підкреслення, це було б неймовірно очевидно.


18
thisКлючове слово гарантованою посилання на поточний об'єкт. Ви не розумієте це підкресленням. Не потрібно ненавидіти this.
Jason S

15
Навіщо вигадувати «стандарт». "це". повідомляє вам, що об'єкт є змінною екземпляра "Class". говорить вам, що це змінна категорія. Все інше є змінною стека. Підкреслення належить до тієї ж купи поганих ідей, де угорська нотація зараз розкладається.
Quarkly

4
@ DRAirey1 занадто легко пропустити це. коли вам це потрібно, і ви в кінцевому підсумку робите дивні речі з державою.
Кріс Марісіч

3
@ChrisMarisic Ви, звичайно, вітаємо вашу думку щодо використання _, але не вважайте це усталеним стандартом, коли цього явно немає.
розчавити

3
Я втратив тебе в "Я продовжив створювати свій власний стиль".
rory.ap

12

Мені подобається підкреслення, тому що тоді я можу використовувати мале ім'я як параметри методу, подібні до цього:

public class Person
{
    string _firstName;

    public MyClass(string firstName)
    {
        _firstName = firstName;
    }

    public string FirstName
    {
        get { return _firstName; }
    }
}

39
публічний рядок FirstName {get; приватний набір; }
язон

3
Ви все ще можете використовувати малий регістр як параметр методу, використовуючи thisключове слово. Зробити це глухим моментом у триваючому та завжди суперечливому «підкресленні чи ні»:public MyClass(string firstName){ this.firstName = firstName; }
mateuscb

5
Це майбутнє, тепер просто, public string FirstName { get; }а сеттер все ще доступний у конструкторі
Кріс Марісіч

У цьому прикладі. thisбуде потрібно лише в конструкторі. Не потрібно його використовувати більше ніде. Так firstNameяк назва поля працює дуже добре.
Томас

9

Мені все ще подобається використовувати підкреслення перед приватними полями з причини, про яку згадував Мартін, а також тому, що приватні поля потім будуть сортуватись в IntelliSense. Це попри злость угорських позначень префіксів взагалі.

Однак останнім часом я вважаю, що використання префіксу підкреслення для приватних членів нахмуриться, хоча я не зовсім впевнений, чому. Можливо, хтось ще знає? Це лише принцип префікса? Або щось було пов’язано з керуванням іменами родових типів, які підкреслюють їх у складених складах чи щось таке?


4
Для мене _ захаращує _words, коли швидко _сканування за допомогою коду, стає менш схожим на просто читання _і _more _like, що потрібно зупинятися на _every _, щоб визнати це та _realize це _не контрольний характер деякого _sort. Це також порушує відступ, практично натискаючи на перший корисний символ у назвах полів один стовпець праворуч. Я, як правило, не люблю C ++, тому що більшість програмістів на C ++ прагнуть писати неймовірно стислі та уповільнені для читання символи /
машиноподібні

23
Для мене це. захаращуючи this.words, коли швидко this.scanning за допомогою коду, стає менш схожим на просто читання this.and this.more this.like, щоб зупинитись, і this.every this. визнати це і це.реалізувати це це.не контрольний характер деякого цього.засоби. Я б вважав за краще знайти випадкові _fieldFooабо _fieldBarзамість того, щоб моє використання було захаращене this.fieldFooабо this.fieldBar. Я вважаю this.префікс набагато більшим, ніж провідним підкресленням.
AggieEric

Я думав, можливо, ця невідповідність досвіду може бути наслідком файлових систем Oldschool або файлів передачі файлів, де не було дозволено пробілів, які навчали деяких користувачів бачити підкреслення як пробіли, а отже, не відволікаючи їх на читання. У мене, з іншого боку, є проблеми з такими іменами, оскільки я з самого початку завжди використовував пробіли у власних іменах ...
Оскар Дювеборн,

1
@AggieEric вдарив нігтем по голові. Тільки читання його речення дає мені голову! Протягом багатьох років я намагався дотримуватися рекомендацій MS у цьому питанні, і мені так важко читати сині thisслова скрізь, що я прийняв тут рішення, яке лютувало. Тепер я релігійно використовую thisТОЛЬКІ посилання на власність, або коли мені потрібно чітко розрізняти thisі base. Думаю, кожен у себе :-)
Riegardt Steyn

1
Я думаю, що це тому, що, зрештою, починати щось із знаку пунктуації шкодить читабельності. Це, здається, не турбує всіх, але мені здається, дуже неприродно читати все, що починається з пунктуації. Чим більше схожий на англійський код, тим легше мені його читати. А в сучасних ІДЕ просто не вдається визначити різницю між місцевими та приватними членами, оскільки вони, швидше за все, будуть різними кольорами.
Тім Лонг

5

Рекомендація Style Cop чи ні, копання до .NET Framework показує багато "_" використання змінних членів. Що б не рекомендували творці Style Cop, це не те, чим користуються працівники MS. :) Тож я буду дотримуватися підкреслення. Оскільки я особисто роблю набагато менше помилок, використовуючи підкреслення, ніж це (наприклад: використання varName = varName замість цього.varName = varName, воно справді застрягло в мені)


3
Підкреслення також рекомендується для посібника зі стилю .NET core: github.com/dotnet/corefx/wiki/Coding-style
landoncz

3

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

public int Foo
{
   private int foo;
   get
   {
      return foo;
   }
   set
   {
      foo = value;
   }
}

Це дозволило б повністю припинити використання полів.

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


Здається, банда C # погоджується з вами з новим приватним int foo {get; set;} синтаксичний цукор.
Дана

О, звичайно; те, що я тут описую, абсолютно безрезультатно.
Роберт Россні

Ви описуєте "Автореалізовані властивості". На жаль, з Visual Basic.NET він фактично використовує "приховану" змінну _prefix за кадром, тобто, якщо у вас була автореалізована властивість "Public Property Foo As Integer", ви могли б НЕ мати декларацію змінної члена "Private _foo as Integer "

Ні, я не описую автоматично реалізовані властивості, принаймні, не в своєму прикладі. Я описую масштабний рівень, який не існує в C # або VB. Дійсно прикро, що VB обрав такий тривіальний спосіб з’єднати імена резервних полів. C # 's досить потворний, що ви ніколи не створили змінну з тим самим іменем випадково.
Роберт Россні

3

Позначення _fieldName для приватних полів так легко зруйнувати . Використовуючи "це". позначення неможливо розірвати. Як би ви порушили _ позначення? Дотримуйтесь:

private void MyMethod()
{
  int _myInt = 1; 
  return; 
}

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

Порівнюйте це з Ruby, коли ім'я змінної @my_numberпов'язує ім'я з областю і є нерозривним.

редагувати: Ця відповідь заперечила негативно. Мені все одно, це залишається.


11
Навряд чи є вагомою критикою конвенції про іменування, щоб сказати, що розробники можуть не дотримуватися цього.
Роберт Россні

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

6
@Konrad: Ви звучаєте претензійно, коли говорите "як вправу для читача". Це не підручник з математики.
jcollum

3
Зараз трохи менше негативу :) Хоча ми можемо веслувати проти течії, я також не люблю конвенцію підкреслення. На мій погляд, це не відрізняється від угорської нотації, і якщо чесно, це змушує мої очі кровоточити (шкодить читабельності). Ми викинули Угорську нотацію за допомогою C #, і настав час викласти цей останній залишок не довіряти IDE.
Тім Лонг

1
Я чув, що MS насправді говорить, що підкреслення не слід використовувати у посібнику зі стилю C #. blogs.msdn.microsoft.com/brada/2005/01/26/… - розділ 2.6 - схоже, що Бред Абрамс погоджується з нами принаймні!
jcollum

1

Якщо ви хочете, щоб ваша збірка відповідала CLS, ви можете використовувати атрибут CLSCompliant у вашому файлі Assemblyinfo. Потім компілятор скаржиться, коли ваш код містить речі, які не відповідають стандартам cls.

Потім, коли у вас є 2 властивості, які відрізняються лише у випадку, компілятор видасть помилку. З іншого боку, коли у вас є приватне поле та публічна власність в одному класі, проблем не буде.

(Але я також завжди префіксую своїх приватних членів підкресленням. Це також допомагає мені зрозуміти, коли я читаю свій код, що певна змінна є полем члена).


0

Мені подобається використовувати підкреслення перед моїми приватними полями з двох причин. Про одне вже згадувалося, поля виділяються з пов'язаних з ними властивостей у коді та в Intellisense. Друга причина полягає в тому, що я можу використовувати ті ж самі умови іменування, чи я кодую в VB чи C #.


1
хто це мудрий? Чи не підкреслення означає, що "продовжується на наступному рядку" у VB?
JBRWilkinson

1
Тільки якщо підкресленням слід пробіл.
Роб Віндзор

Початковий лист,
малий чи великий

0

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

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