коллеги!
хотела бы спросить вопросы, которые у меня возникли при более подробном изучении языка .NET и трудности касаются как минимум ссылочного типа string
1) Intern pool; (пулСтрок) Позволяет объединить строки с одинаковыми значениями в них в определенный пул памяти. В данном случае мы инициализировали две строки с одинаковыми значениями и они попали в один пул памяти. пример в моем понимании:
string a = "aaa";
string b = "aaa";
bool c = (object)a == (object) b; // И получаем true
ОДНАКО код:
string a = "aaa";
string b = "aa";
b+="a";
bool c = (object)a == (object) b; // И получаем false
Почему так? и как это работает? по сути мы получаем строку с одинаковыми значениями и все они должны ссылаться на один объект. почему мы по итогу получаем разные результаты? Я понимаю, что в данном случае мы сравниваем объекты, а не содержимое. Но почему они не объединились?
В первом вашем примере строки интернируются на этапе компиляции. Если посмотреть в утилите ILDASM, то в окне MetaInfo в разделе User Strings будет представлен всего один экземпляр:
70000001 : ( 3) L"aaa"
Соответственно, обе переменные: и a
, и b
будут указывать на этот адрес.
Во втором примере в результате конкатенации тоже получается строка "aaa", но она не заносится по умолчанию в пул интернированных строк, потому что для этого нужны дополнительные проверки, то есть тратится время.
Во втором примере можно добавить строку в пул вручную:
string a = "aaa";
string b = "aa";
b += "a";
b = string.Intern(b);
bool c = (object)a == (object)b; // True
Ответ на вопрос из комментария:
Я не уверен, но, думаю, выгода в том, что после интернирования переменная b
станет указывать на тот же участок памяти, что и a
. После чего сборщик мусора сможет убрать другой экземпляр строки "aaa". Это почти бессмысленно для коротких строк, но может оказаться выгодно для длинных долгоживущих строк.
Также нужно учитывать, что удалить строку из пула невозможно. Она так и будет висеть в памяти до конца работы приложения. Именно поэтому в рантайме строки не добавляются в пул по умолчанию.
Чтобы не гадать, глянем сразу IL-инструкции которые генерирует компилятор:
IL_0000: nop
IL_0001: ldstr "aaa"
IL_0006: stloc.0 // a
IL_0007: ldstr "aaa"
IL_000C: stloc.1 // b
IL_000D: ldloc.0 // a
IL_000E: ldloc.1 // b
IL_000F: ceq
IL_0011: stloc.2 // c
IL_0012: ldstr "aaa"
IL_0017: stloc.3 // a2
IL_0018: ldstr "aa"
IL_001D: stloc.s 04 // b2
IL_001F: ldloc.s 04 // b2
IL_0021: ldstr "a"
IL_0026: call System.String.Concat
IL_002B: stloc.s 04 // b2
IL_002D: ldloc.3 // a2
IL_002E: ldloc.s 04 // b2
IL_0030: ceq
IL_0032: stloc.s 05 // c2
IL_0034: ret
Как видим в данном случае в первом блоке мы записали одну и ту же строку в a
(IL_0006) и b
(IL_000C), и в данном случае строка является интернированной, во втором же блоке только 'a2'(IL_0017) является интернированной, b2
после конкатенации (IL_0026) и присваивания (IL_002B) таковой не является.
UPD: Следующий код также возвращает false
:
Console.WriteLine(ReferenceEquals(b2, a2));
Метод ReferenceEquals
определяет, совпадают ли указанные экземпляры Object
.
При сравнении строк. Если objA
и objB
являются строками, ReferenceEquals
возвращает true
если строки интернированы. Он не выполняет проверку на равенство значений. В следующем примере s1
и s2
равны, поскольку они являются двумя экземплярами одной интернированной строки. Тем не менее s3
и s4
не равны, поскольку несмотря на то, что они имеют идентичные строковые значения, эти строки не интернированы.
using System;
public class Example
{
public static void Main()
{
String s1 = "String1";
String s2 = "String1";
Console.WriteLine("s1 = s2: {0}", Object.ReferenceEquals(s1, s2));
Console.WriteLine("{0} interned: {1}", s1,
String.IsNullOrEmpty(String.IsInterned(s1)) ? "No" : "Yes");
String suffix = "A";
String s3 = "String" + suffix;
String s4 = "String" + suffix;
Console.WriteLine("s3 = s4: {0}", Object.ReferenceEquals(s3, s4));
Console.WriteLine("{0} interned: {1}", s3,
String.IsNullOrEmpty(String.IsInterned(s3)) ? "No" : "Yes");
}
}
// The example displays the following output:
// s1 = s2: True
// String1 interned: Yes
// s3 = s4: False
// StringA interned: No
P.s.:
Метод также возвратит false
при сравнении типов значений, если objA
и objB
являются типами значений, упакованы перед передачей в ReferenceEquals
и
представляют одно и то же значение.
int int1 = 3;
Console.WriteLine(Object.ReferenceEquals(int1, int1)); //False
Console.WriteLine(int1.GetType().IsValueType); //True
Виртуальный выделенный сервер (VDS) становится отличным выбором
Пытаюсь преобразовать один Expression<Func<double, double>> в другой, однако при попытке компиляции полученного выражения, появляется ошибка
С помощью SimpleBrowser заполняю поля логина и пароля и имитирую нажатие кнопки, после чего происходит вход на сайтДалее из объекта извлекаю файлы...
Посоветуйте как без создания дополнительных переменных реализовать такое:
Я создал скрипт C# в котором есть несколько функций и функция ChooseResolution()Прицепил его на пустой объект UIManager, который засунул в поле для объектов...