Ответ 1
Удивительно, но это зависит.
Если вы сделаете это в методе:
void Foo() {
String one = "1";
String two = "2";
String result = one + two + "34";
Console.Out.WriteLine(result);
}
то компилятор, кажется, испускает код с помощью String.Concat
, как ответил @Joachim (+1 к нему кстати).
Если вы определяете их как константы, например:
const String one = "1";
const String two = "2";
const String result = one + two + "34";
или литералы, как в исходном вопросе:
String result = "1" + "2" + "3" + "4";
тогда компилятор будет оптимизировать эти знаки +
. Это эквивалентно:
const String result = "1234";
Кроме того, компилятор удалит посторонние постоянные выражения и только испустит их, если они будут использованы или открыты. Например, эта программа:
const String one = "1";
const String two = "1";
const String result = one + two + "34";
public static void main(string[] args) {
Console.Out.WriteLine(result);
}
Только генерирует одну строку - константу result
(равную "1234" ). one
и two
не отображаются в полученном IL.
Имейте в виду, что во время выполнения могут быть дополнительные оптимизации. Я просто иду по тому, что ИЛ производится.
Наконец, что касается интернирования, то константы и литералы интернированы, но значение, которое интернировано, является конечным постоянным значением в IL, а не буквальным. Это означает, что вы можете получить меньшее количество строковых объектов, чем вы ожидаете, поскольку множество идентично определенных констант или литералов будут фактически одним и тем же объектом! Это иллюстрируется следующим:
public class Program
{
private const String one = "1";
private const String two = "2";
private const String RESULT = one + two + "34";
static String MakeIt()
{
return "1" + "2" + "3" + "4";
}
static void Main(string[] args)
{
string result = "1" + "2" + "34";
// Prints "True"
Console.Out.WriteLine(Object.ReferenceEquals(result, MakeIt()));
// Prints "True" also
Console.Out.WriteLine(Object.ReferenceEquals(result, RESULT));
Console.ReadKey();
}
}
В случае, когда строки конкатенируются в цикле (или иначе динамически), вы получаете одну дополнительную строку для каждой конкатенации. Например, следующее создает 12 строковых экземпляров: 2 константы + 10 итераций, каждый из которых приводит к новому экземпляру String:
public class Program
{
static void Main(string[] args)
{
string result = "";
for (int i = 0; i < 10; i++)
result += "a";
Console.ReadKey();
}
}
Но (также удивительно), несколько последовательных конкатенаций объединяются компилятором в одну конкатенацию нескольких строк. Например, эта программа также генерирует только 12 экземпляров строки! Это связано с тем, что " Даже если вы используете несколько операторов в одном из операторов, содержимое строки копируется только один раз."
public class Program
{
static void Main(string[] args)
{
string result = "";
for (int i = 0; i < 10; i++)
result += "a" + result;
Console.ReadKey();
}
}