Чи потрібно в C # використовувати рядок.Empty або String.Empty або “” для того, щоб ініціалізувати рядок?


705

У C # я хочу ініціалізувати значення рядка з порожнім рядком.

Як мені це зробити? Який правильний шлях, і чому?

string willi = string.Empty;

або

string willi = String.Empty;

або

string willi = "";

або що?


7
Дивіться також цю подібне обговорення для Java: stackoverflow.com/questions/213985 / ...
Harpo

39
краще використовувати String.IsNullOrEmpty (рядок myString), звичайно?
ZombieSheep

3
Я використовую [string.IsNullOrWhiteSpace (stringvalue)] ... працює в .Net 4.0. Для ініціалізації я просто використовую: [var text = "";] Простий, читабельний і потребує найменшого часу для набору :)
Джалал Ель-Шейр

61
Що важливіше - веселе ім’я вашої змінної.
Арж

5
Те, що мене зацікавило, це те, чому є навіть власність "Порожні". Це приємно і все, але не обов’язково і повно.
MasterMastic

Відповіді:


807

Використовуйте все, що ви та ваша команда вважаєте найбільш читабельним.

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

Однак те, що вам здається більш зрозумілим - це інша справа. Це суб'єктивно і змінюватиметься від людини до людини - тому я пропоную вам дізнатися, що подобається більшості людей у ​​вашій команді, і всі йти з цим для послідовності. Особисто мені ""легше читати.

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


75
Ваші очі можуть обдурити вас, коли ви очікуєте побачити "", ви можете легко помилитися "" за "". Ось чому легше редагувати те, що написав хтось інший. Ваш мозок не має заздалегідь продуманих уявлень про текст, тому легше вибрати аномалії.
tvanfosson

125
@tvanfosson: Тож вас (або колегу) насправді укусив це як помилка? Я підозріло ставляться до подібного роду претензій, без того, щоб вони насправді викликали проблеми. Я використовую "" роками, але ніколи не помиляюся ...
Джон Скіт

34
Особисто я завжди використовував String.Empty, я використовую капітал 'S' всякий раз, коли хочу використовувати статичний метод на рядку, це просто особиста перевага, яка дозволяє мені відрізняти тип від змінної. Але це лише перенесення від використання StringUtils.EMPTY в commons.lang від java. Один із цікавих моментів - я майже сліпий, і це, безумовно, допомагає в читанні для мене.
Бретт Райан

79
Ви дали мені натхнення почати розвиватися в Times New Roman.
Justin Rusbatch

73
З якої - то незрозумілої причини string.Emptyне є постійною величиною . Це означає, що в ряді випадків, коли потрібна константа часу компіляції, string.Emptyнавіть не є законною. Сюди входять case ""блоки в switchоператорах, значення за замовчуванням необов'язкових параметрів , параметри та властивості при застосуванні атрибутів та безліч інших ситуацій (залишено читачеві). Отже, враховуючи, що string.Emptyце заборонено в деяких поширених ситуаціях, краще використовувати ""конвенцію -верху.
Джеппе Стіг Нільсен

375

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

Дивлячись на код за кадром, ви також не бачите різниці. Єдина відмінність полягає в ІЛ, які string.Emptyвикористовують опкод ldsfld і ""використовують опкод ldstr, але це лише тому, що string.Emptyє статичним, і обидві інструкції роблять те саме. Якщо ви подивитеся на збірку, яка виробляється, вона точно така ж.

C # код

private void Test1()
{
    string test1 = string.Empty;    
    string test11 = test1;
}

private void Test2()
{
    string test2 = "";    
    string test22 = test2;
}

Код ІЛ

.method private hidebysig instance void 
          Test1() cil managed
{
  // Code size       10 (0xa)
  .maxstack  1
  .locals init ([0] string test1,
                [1] string test11)
  IL_0000:  nop
  IL_0001:  ldsfld     string [mscorlib]System.String::Empty
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ret
} // end of method Form1::Test1
.method private hidebysig instance void 
        Test2() cil managed
{
  // Code size       10 (0xa)
  .maxstack  1
  .locals init ([0] string test2,
                [1] string test22)
  IL_0000:  nop
  IL_0001:  ldstr      ""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ret
} // end of method Form1::Test2

Код складання

        string test1 = string.Empty;
0000003a  mov         eax,dword ptr ds:[022A102Ch] 
0000003f  mov         dword ptr [ebp-40h],eax 

        string test11 = test1;
00000042  mov         eax,dword ptr [ebp-40h] 
00000045  mov         dword ptr [ebp-44h],eax 
        string test2 = "";
0000003a  mov         eax,dword ptr ds:[022A202Ch] 
00000040  mov         dword ptr [ebp-40h],eax 

        string test22 = test2;
00000043  mov         eax,dword ptr [ebp-40h] 
00000046  mov         dword ptr [ebp-44h],eax 

13
@PrateekSaluja: Щоб побачити IL, ви можете використовувати ildasm.exe, який постачається з Visual Studio. Щоб побачити демонтаж, скористайтеся вікном "Розбирання" у меню налагодження, коли ви потрапили на точку зламу (працює і в коді випуску).
Томас Братт

1
Ненавиджу, що я збираюся рекомендувати цей продукт .. АЛЕ рефлектор дозволяє вибирати мову під час розбирання джерела, а IL - це варіант! ILDASM щойно датується почуттю ... Команда інструментів MS не здається шліфувати чи випускати хороші інструменти!
felickz

80

Найкращий код - це зовсім не код :

Фундаментальний характер кодування полягає в тому, що наше завдання, як програмістів, - визнати, що кожне рішення, яке ми приймаємо, є компромісним. […] Почніть з стислості. Збільште інші розміри відповідно до тестування.

Отже, менше коду краще код: Воліють ""в string.Emptyабо String.Empty. Ці два в шість разів більше, але без додаткової вигоди - звичайно, без додаткової ясності, оскільки вони виражають ту саму інформацію.


1
але в C # ми можемо просто сказати string.IsNullOrWhitespace (s): p
felickz

31
Я погоджуюся, що код повинен бути якомога меншим, але, як правило, не стверджують, що менше символів - це завжди кращий код. Що стосується, наприклад, називання змінних, розумна кількість символів, як правило, призводить до кращих імен, ніж просто використання i та j.
Маркус Мейєр

3
@Markus Це в значній мірі залежить: для змінного циклу , що представляють собою індекс, i це краще , ніж довге ім'я змінного. Навіть загальніші, кращі імена змінних, які передають ту саму інформацію , з однаковою чіткістю, завжди бажані. Просто для того, щоб висловити необхідну інформацію, вам потрібна певна довжина символів, і я цього не заперечую (ніхто не є).
Конрад Рудольф

2
@Konrad: я є гарною назвою змінної, лише якщо цикл невеликий і він не містить інших індексів. Але я згоден, що якщо што-н. можна сказати коротше, передаючи ту саму інформацію, яка була б кращою, як у випадку string.Empty / "". String.Empty не додає ясності.
Маркус Мейєр

Для мене: string.Empty говорить, що цей рядок є і повинен бути порожнім весь час, тоді як "" каже, що під час написання цього рядка може бути порожнім, але ви можете його змінити.
аерозон

54

Одна відмінність полягає в тому, що якщо ви використовуєте switch-caseсинтаксис, ви не можете писати, case string.Empty:оскільки це не константа. Ви отримуєтеCompilation error : A constant value is expected

Перегляньте це посилання для отримання додаткової інформації: рядки-порожні-проти-порожні-котирування


22
switchЗатвердження один дуже хороший приклад. Крім того, якщо ви робите необов'язковий параметр, наприклад void MyMethod(string optional = "") { ... }, його також неможливо використовувати string.Empty. І тоді, звичайно, якщо ви хочете визначити constполе або локальну змінну, const string myString = "";знову ""це єдиний варіант. Якби тільки string.Emptyбуло постійне поле, різниці не було б. Але це не так, тому в деяких випадках доводиться користуватися "". То чому б не використовувати ""весь час?
Джеппе Стіг Нільсен

5
Це дійсно вагомий аргумент, оскільки використання string.Emptyперешкоджає досягти послідовності в кодовій базі: ви повинні використовувати дві різні сутності, щоб виразити одне і те ж. І щоб додати до списку речей, які ви не можете зробити: ви не можете використовувати string.Emptyз атрибутами .
Pragmateek

2
Дуже хороші бали! Посилання розірвано. Ось копія вмісту: web.archive.org/web/20131230161806/http://kossovsky.net/…
ygoe

42

Я волів би , stringщоб String. вибираючи string.Emptyбільш ""є питанням вибору одного і приклеїти з ним. Перевагою використання string.Emptyє те, що це дуже очевидно, що ви маєте на увазі, і ви випадково не копіюєте на символи, що не друкуються, як "\x003"у вашому "".


101
Я заперечую, що якщо ви випадково скопіюєте символи, що не надруковані у свій код, у вас виникнуть більші проблеми, ніж у цьому питанні;)
Джон Скіт

9
ASCII \ 003 - це роздільник поля для B2B-повідомлень, з якими я працював :)
Джиммі

7
(Я також пропоную уникати \ x escape, btw - занадто важко помітити різницю між "\ x9Bad Compiler" та "\ x9Good Compiler", які мають докорінно різні результати!)
Джон Скіт

Особисто я віддаю перевагу String над рядком, коли викликає статичний метод на String. Однак я майже сліпий, і це особиста перевага, яку я нікого не виконую.
Бретт Райан,

2
@Jimmy Sure, але ми говорили про порожню рядок. ""Я стверджую, що аргумент, який є небезпечним, коли копіювання / вставлення недійсне, тому що ви ніколи не копіюєте / вставляєте порожній рядок. Щодо інших рядків, звичайно, завжди слід пам’ятати про щось.
Тимо

22

Я не збирався звучати, але я бачу, що тут викидається якась неправильна інформація.

Я, особисто, віддаю перевагу string.Empty. Це особиста перевага, і я схиляюся до волі будь-якої команди, з якою працюю в кожному конкретному випадку.

Як згадували деякі інші, різниці між string.Emptyі між ними взагалі немає String.Empty.

Крім того, і це маловідомий факт, використання "" цілком прийнятно. Кожен екземпляр "" "в інших середовищах створюватиме об'єкт. Однак .NET інтернує його рядки, тому майбутні екземпляри витягуватимуть ту саму незмінну рядок із пулу інтернів, і будь-яке звернення до продуктивності буде незначним. Джерело: Бред Абрамс .


20
Я не бачу, чому "технічно" кожен екземпляр "" створить об'єкт. Це не просто випадковість, що рядки інтерновані - це в специфікації C #.
Джон Скіт

15

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


13

String.Emptyі string.Emptyє рівнозначними. String- ім'я класу BCL; stringце його псевдонім C # (або ярлик, якщо ви хочете). Те саме, що Int32і з int. Докладні приклади див. У документах .

Що ""стосується, я не дуже впевнений.

Особисто я завжди користуюся string.Empty.


10

Практично кожен розробник там знатиме, що означає "". Я особисто зіткнувся з String.Порожні вперше, і мені довелося витратити деякий час на пошук Google, щоб з'ясувати, чи справді вони - це те саме.


3
Це загальнодоступне рядкове рядкове поле і його значення "" ... чому це зміниться?
Метью Віт

5
Ви пропускаєте пункт, який робить @Jason. Звідки ви знаєте, що це вперше ви бачите string.Empty? Чи знаєте ви, що ви ""вперше побачили це?
David R Tribble

10

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

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

У разі ініціалізації з string.Emptyцим попередженням компілятора

CS0219 - The variable 'x' is assigned but its value is never used

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

Така поведінка пояснюється у статті Connect за цим посиланням: https://connect.microsoft.com/VisualStudio/feedback/details/799810/c-warning-cs0219-not-reported-when-assign-non-constant-value

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


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

2
Цікаво. Зауважте, що var unused = "literal";компілятор може повністю оптимізувати (видалити) декларацію . Він не може мати побічних ефектів. З іншого боку, var unused = MyClass.Member;його не можна видалити повністю. Це тому, що читання Memberможе мати побічні ефекти. Якщо Memberє статична властивість з getаксесуаром, зрозуміло, що дзвінок до геттера повинен зберігатися. Але навіть якщо Memberце статичне поле, може виникнути побічний ефект, який може працювати статичний конструктор. Звичайно, було б погано мати стиль кодування . Але вам потрібна пустушка для читання Member.
Jeppe Stig Nielsen

9

Я провів цей дуже простий тест, використовуючи наступний метод у консольній програмі:

private static void CompareStringConstants()
{
    string str1 = "";
    string str2 = string.Empty;
    string str3 = String.Empty;
    Console.WriteLine(object.ReferenceEquals(str1, str2)); //prints True
    Console.WriteLine(object.ReferenceEquals(str2, str3)); //prints True
}

Це чітко говорить про те, що всі три змінні, а саме str1, str2і str3хоча вони ініціалізовані за допомогою різного синтаксису, вказують на абсолютно той самий рядковий (нульової довжини) об’єкт у пам'яті. Я провів цей тест у консольній програмі .NET 4.5. Отже, всередині них немає різниці, і все це зводиться до зручності, яку ви хочете використовувати як програміст. Така поведінка рядкового класу відома як строкове інтернування в .NET. Ерік Ліпперта має дуже хороший блог тут , описує цю концепцію.


8

Будь-яке з перерахованого вище.

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


7

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


7

Ніхто не згадував, що у VisualStudio String кольорово кодується інакше, ніж рядок. Що важливо для читабельності. Крім того, нижній регістр зазвичай використовується для vars і type, не велика справа, але String.Empty - це константа, а не var або type.


String.Empty не є константою: див. Stackoverflow.com/questions/507923/… Це фактично екземпляр класу String, за задумом. А розфарбовування згадувалося раніше, хоч трохи приховано: stackoverflow.com/questions/263191/…
Майкл

6

stringє синонімом до System.Stringтипу, Вони однакові.

Значення також ідентичні: string.Empty == String.Empty == ""

Я б не використовував "" константи символів у коді, швидше, string.Emptyабо String.Empty- простіше зрозуміти, що означає програміст.

Між, stringі Stringмені подобається нижній регістр stringбільше лише тому, що я працював з Delphi протягом багатьох років, і стиль Delphi - це малі літери string.

Отже, якби я був вашим начальником, ви б писали string.Empty


6

Я вважала за краще б string.Emptyбільш String.Emptyтому , що ви можете використовувати його без необхідності включати using System;в файл.

Що стосується вибору ""більш string.Empty, це особисті переваги і має бути прийнято вашою командою.


2
Я єдиний член команди, як я приймаю рішення? кинути кістки?
Gqqnbig

1
Для тих, кому може бути цікаво, як можна використовувати string.Emptyконстанту без імпорту using Systemпростору імен - Ключові слова в C # просто перетворяться на їх цілком кваліфіковане ім'я, яке включає простір імен, а також перед тим, як записати як MSIL у висновку * .dll або *. файл EXE. Настільки ефективно string.Emptyвиписується System.String.Emptyкомпілятором як у MSIL. І як ви вже можете знати, що якщо ви згадуєте повноцінне ім’я типу, то ви можете пропустити імпорт просторів імен у верхній частині файла коду.
RBT

5

Я не маю значення. Останній - це найшвидший набір :)


4

Не має значення - вони точно те саме. Однак головне, щоб ви були послідовними

ps Я весь час боюся з таким "правильним".


1
У сучасному світі "послідовний" означає послідовність у всіх командах у всьому світі, що є однією з цілей StackOverflow. Якщо я можу запропонувати, давайте скористаємося String.Empty.
Павло Радзівіловський

1
У деяких мовах немає порожньої константи, і всі мови, які я можу дозволити, дозволяють "" нульову строку. Тому я голосую за "" відповідність іншим мовам. :)
TomXP411

4

Це абсолютно перевагу в кодовому стилі, виконайте, як .NET обробляє рядки. Однак ось мої думки :)

Я завжди використовую імена типу BCL під час доступу до статичних методів, властивостей та полів: String.Emptyабо Int32.TryParse(...)абоDouble.Epsilon

Я завжди використовую ключові слова C # при оголошенні нових екземплярів: int i = 0;абоstring foo = "bar";

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


3

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


3

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

[EDIT]

Крім того, ви можете завжди використовувати stringабо Stringконсистенцію, але це тільки я.


Я погоджуюся з цим зауваженням, але все одно живу небезпечно, коли мені лінь. У будь-якому випадку, я не думаю, що в мене є привід написати код, який використовує рядок, перед тим, як призначити його поза декларацією змінної. Насправді мені дратує те, що я взагалі повинен ініціалізувати свої рядки, незважаючи на ризики.
EnocNRoll - AnandaGopal Pardue

3

Я особисто був свідком "", що спричиняв (незначні) проблеми двічі. Один раз був пов’язаний з помилкою молодшого розробника, нового в командному програмуванні, а інший був простим друком, але факт використання string.Empty дозволив би уникнути обох питань.

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

Якщо ви введете string.EMpty або Strng.Empty, компілятор дає вам знати, що ви зробили це неправильно. Відразу. Він просто не складеться. Як розробник ви посилаєтесь на певні наміри, які компілятор (або інший розробник) жодним чином не може витлумачити неправильно, і коли ви зробите це неправильно, ви не можете створити помилку.

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

Задовго до string.Empty була річ, я використовував стандартну бібліотеку, яка визначала константу EMPTY_STRING. Ми все ще використовуємо цю константу в операторах випадків, коли string.Empty не дозволено.

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

Специфіка та складання часу виконання. Це що на вечерю.


3

Я використовую "", оскільки він буде в кольорі виразно жовтим ... чомусь String.Empty - це все біле в моїй темі Visual Studio Code. І я вважаю, що для мене це найбільше важливо.


2

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


2

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

Розглянемо наступний код C # ...

(customer == null) ? "" : customer.Name

проти

(customer == null) ? string.empty : customer.Name

Я особисто вважаю останнє менш неоднозначним і легшим для читання.

Як зазначають інші, фактичні відмінності незначні.


1

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


1

Хоча різниця дуже, ДУЖЕ мало, різниця все ще існує.

1) "" створює об'єкт, коли String.Empty не робить. Але цей об'єкт буде створений один раз і буде посилатися з пулу рядків пізніше, якщо у вас є інший "" код.

2) Рядок і рядок однакові, але я б рекомендував використовувати String.Empty (як і String.Format, String.Copy тощо), оскільки позначення крапок вказують на клас, а не на оператор, а клас, що починається з великої літери, відповідає Стандарти кодування C #.


1
string.Empty є "", перевірте джерело
dss539

1

На http://blogs.msdn.com/b/brada/archive/2003/04/22/49997.aspx :

Як випливає з Девіда, різниці між ними є String.Emptyі ""досить малі, але є різниця. ""насправді створюється об’єкт, він, ймовірно, буде витягнутий з пулу інтернів, але все ж ... поки String.Emptyстворює жоден об'єкт ... тому, якщо ви справді шукаєте в кінцевому рахунку ефективність пам'яті, я пропоную String.Empty. Однак ви повинні пам’ятати, що різниця настільки дрібницька, що вам сподобається ніколи не бачити її у своєму коді…
Щодо System.String.Emptyабо string.Emptyабо String.Empty… мій рівень догляду низький ;-)


1
Ця публікація в блозі MSDN була в 2003 році .... Ви впевнені, що це все ще стосується останніх версій .NET ?!
Карстен Шютте

@ CarstenSchütte: Мені здається, що така функція не має на меті сильно змінитись ... і якщо вона була, то в Інтернеті про це почулися певні шуми.
sergiol

3
@sergiol Якщо поле є більш ефективним, ніж буквальне, це однозначно помилка продуктивності. Тож є сподівання, що це буде вже виправлено.
Конрад Рудольф

1

Порожня рядок - це як порожній набір просто ім'я, яке всі використовують для виклику "". Також у формальних мовах рядки, створені з алфавіту, які мають нульову довжину, називаються порожнім рядком. І набір, і рядок мають спеціальний символ для цього. Порожній рядок: ε та порожній набір: ∅. Якщо ви хочете поговорити про цей рядок нульової довжини, ви назвете його порожнім рядком, щоб усі точно знали, про що ви маєте на увазі. Тепер, якщо ви назвали його порожнім рядком, чому б не використовувати його string.Emptyв коді, його показник має намір явний. Недоліком є ​​те, що він не є постійним і тому недоступний скрізь, як в атрибутах. (З технічних причин це не є постійною, див. Довідкове джерело.)


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