В общем, когда вы включаете оптимизацию в компиляторе C# it attempts to minimize the number of temporary/local variable storage slots used in methods. Поэтому вы не должны заботиться о том, чтобы свести к минимуму количество переменных, потому что компилятор сделает это за вас. Без оптимизаций будут некоторые различия, потому что цель состоит в том, чтобы улучшить опыт отладки и сохранить как можно больше информации.
В этом конкретном случае точно такой же IL испускается для обоих методов, когда оптимизация включена.Вот полный фрагмент кода, включая тип значения и ссылочный тип для сравнения:
using System;
public class C {
private static MyStruct NewStructLocal()
{
var s = new MyStruct();
return s;
}
private static MyStruct NewStructReturn()
{
return new MyStruct();
}
private static MyClass NewClassLocal()
{
var s = new MyClass();
return s;
}
private static MyClass NewClassReturn()
{
return new MyClass();
}
}
public struct MyStruct
{
public int I;
}
public class MyClass
{
public int I;
}
И излучаемый IL является:
.method private hidebysig static
valuetype MyStruct NewStructLocal() cil managed
{
// Method begins at RVA 0x2054
// Code size 10 (0xa)
.maxstack 1
.locals init (
[0] valuetype MyStruct
)
IL_0000: ldloca.s 0
IL_0002: initobj MyStruct
IL_0008: ldloc.0
IL_0009: ret
} // end of method C::NewStructLocal
.method private hidebysig static
valuetype MyStruct NewStructReturn() cil managed
{
// Method begins at RVA 0x206c
// Code size 10 (0xa)
.maxstack 1
.locals init (
[0] valuetype MyStruct
)
IL_0000: ldloca.s 0
IL_0002: initobj MyStruct
IL_0008: ldloc.0
IL_0009: ret
} // end of method C::NewStructReturn
.method private hidebysig static
class MyClass NewClassLocal() cil managed
{
// Method begins at RVA 0x2082
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void MyClass::.ctor()
IL_0005: ret
} // end of method C::NewClassLocal
.method private hidebysig static
class MyClass NewClassReturn() cil managed
{
// Method begins at RVA 0x2082
// Code size 6 (0x6)
.maxstack 8
IL_0000: newobj instance void MyClass::.ctor()
IL_0005: ret
} // end of method C::NewClassReturn
Таким образом, насколько производительность, то они будут идентичны.
В случае ссылочных типов объект создается, ссылка помещается в верхнюю часть оценочного стека и немедленно возвращается оттуда.
В случае типов значений объявляется локальное хранилище, значение в месте хранения инициализируется, значение снова загружается и возвращается. Это довольно типично для типов значений, которые не являются примитивными типами.
Более общий элемент, о котором нужно подумать, заключается в том, что в методе любой значимой сложности компилятор генерирует много неназванных времен, которые не имеют имен, доступных для программиста. Что касается производительности, то беспокоиться о том, сколько названных локальных переменных вы видите в коде, тратит ваше время на беспокойство о неправильном.
Примечание
Этот вопрос несколько изменился, так как я первый написал этот ответ, но я думаю, что все этого анализа до сих пор стоит. В конкретном случае, учитывая, что вы получаете то же IL в обоих методах при компиляции с оптимизацией. Локальная переменная не влияет на испускаемый ИЛ. Теперь, если вы хотите добавить больше локальных переменных для других аргументов, у вас будет другой ИЛ, и вам нужно будет проверить разборку, чтобы определить полную разницу.
На самом деле этого не произойдет, вы не пытались возвратить 'newObject' в первом блоке. И поскольку это ссылочный тип, когда он возвращает 'new MyObject()' во втором блоке, он просто возвращает ссылку на ранее существовавшее выделение памяти для него, поэтому он не будет создавать/уничтожать и дополнительную переменную. –
@AlexeiLevenkov Не все оптимизации. Некоторые оптимизации выполняются самим компилятором C#. –
Удивительно, почему мой комментарий удален ... Вопрос даже утверждает: * Будет ли ** компилятор ** оптимизировать это *, так почему мы говорим о JIT вместо IL? –