Подтвердить что ты не робот

Преимущества использования const вместо переменных внутри методов

Всякий раз, когда у меня есть локальные переменные в методе, ReSharper предлагает преобразовать их в константы:

// instead of this:
var s = "some string";
var flags = BindingFlags.Public | BindingFlags.Instance;

// ReSharper suggest to use this:
const string s = "some string";
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

Учитывая, что это действительно постоянные значения (а не переменные), я понимаю, что ReSharper предлагает изменить их на const.

Но кроме этого есть ли другое преимущество при использовании const (например, более высокая производительность), которое оправдывает использование const BindingFlags вместо удобного и читаемого ключевого слова var?

BTW: Я просто нашел здесь такой же вопрос: Resharper всегда предлагает мне создать строку const вместо строки, но я думаю, что это больше о полях класса где мой вопрос касается локальной переменной/consts.

4b9b3361

Ответ 1

Компилятор выдаст ошибку, если вы попытаетесь присвоить значение константе, что может помешать вам случайно ее изменить.

Кроме того, обычно существует небольшое преимущество в производительности для использования констант и переменных. Это связано с тем, как они скомпилированы в MSIL, за этот журнал MSDN Q & A:

Теперь, где myInt ссылается в коде, вместо того, чтобы делать "ldloc.0", чтобы получить значение из переменной, MSIL просто загружает постоянное значение, которое жестко закодировано в MSIL. Как правило, обычно используется небольшое преимущество производительности и памяти для использования констант. Однако для их использования вы должны иметь значение переменной во время компиляции и любые ссылки на эту константу во время компиляции, даже если они находятся в другой сборке, будет сделана эта замена.

Константы, безусловно, полезный инструмент, если вы знаете значение во время компиляции. Если вы этого не сделаете, но хотите убедиться, что ваша переменная задана только один раз, вы можете использовать ключевое слово readonly в С# (которое соответствует initinly в MSIL), чтобы указать, что значение переменной может быть установлено только в конструкторе; после этого, это ошибка, чтобы изменить его. Это часто используется, когда поле помогает определить личность класса и часто устанавливается равным параметру конструктора.

Ответ 2

В соответствии с моим пониманием значения Const не существуют во время выполнения, т.е. в виде переменной, хранящейся в некоторой ячейке памяти, - они встроены в код MSIL во время компиляции. И, следовательно, это повлияет на производительность. Более того, во время выполнения не требуется выполнять какие-либо операции по хранению (проверки конверсии/сборка мусора и т.д.) На них, где, поскольку переменные требуют этих проверок.

Ответ 3

tl; dr для локальных переменных с буквальными значениями, const имеет никакого значения.


Ваше различие "внутренних методов" очень важно. Давайте посмотрим на него, а затем сравним его с полями const.

Константные локальные переменные

Единственное преимущество локальной переменной const заключается в том, что значение не может быть переназначено.

Однако const ограничивается примитивными типами (int, double ,...) и string, что ограничивает ее применимость.

Отклонение. Есть предложения для компилятора С#, чтобы разрешить более общую концепцию "readonly" locals (здесь), которая распространит это преимущество на другие сценарии. Они, вероятно, не будут считаться const, и, вероятно, будут иметь другое ключевое слово для таких объявлений (например, let или readonly var или что-то в этом роде).

Рассмотрим эти два метода:

private static string LocalVarString()
{
    var s = "hello";
    return s;
}

private static string LocalConstString()
{
    const string s = "hello";
    return s;
}

В режиме Release мы видим следующий (сокращенный) IL:

.method private hidebysig static string LocalVarString() cil managed 
{
    ldstr        "hello"
    ret          
}

.method private hidebysig static string LocalConstString() cil managed 
{
    ldstr        "hello"
    ret          
}

Как вы можете видеть, оба они производят то же самое ИЛ. Независимо от того, является ли локальный s const или нет, это не влияет.

То же самое верно для примитивных типов. Вот пример использования int:

private static int LocalVarInt()
{
    var i = 1234;
    return i;
}

private static int LocalConstInt()
{
    const int i = 1234;
    return i;
}

И снова ИЛ:

.method private hidebysig static int32 LocalVarInt() cil managed
{
    ldc.i4       1234
    ret          
}

.method private hidebysig static int32 LocalConstInt() cil managed
{
    ldc.i4       1234
    ret     
}

Поэтому снова мы не видим разницы. Здесь не может быть производительности или памяти. Единственное отличие заключается в том, что разработчик не может повторно назначить символ.

Поля Const

Сравнение const поля с переменным полем отличается. Неконсольное поле должно быть прочитано во время выполнения. Итак, вы в конечном итоге с IL:

// Load a const field
ldc.i4       1234

// Load a non-const field
ldsfld       int32 MyProject.MyClass::_myInt

Ясно, что это может привести к разнице в производительности, предполагая, что JIT не может встроить в себя постоянное значение.

Еще одно важное отличие здесь - это публичные константные поля, которые разделяются между сборками. Если одна сборка предоставляет поле const, а другая использует ее, то фактическое значение этого поля копируется во время компиляции. Это означает, что если сборка, содержащая поле const, будет обновлена, но сборка не будет скомпилирована, тогда будет использовано старое (и, возможно, неправильное) значение.

Ответ 4

const - это константа времени компиляции - это означает, что весь ваш код, который использует переменную const, скомпилирован, чтобы содержать константное выражение, содержащее константную переменную - испущенный IL будет содержать это постоянное значение.

Это означает, что размер памяти меньше для вашего метода, потому что константа не требует выделения какой-либо памяти во время выполнения.

Ответ 5

Значение const также "разделяется" между всеми экземплярами объекта. Это может привести к снижению использования памяти.

В качестве примера:

public class NonStatic
{
    int one = 1;
    int two = 2;
    int three = 3;
    int four = 4;
    int five = 5;
    int six = 6;
    int seven = 7;
    int eight = 8;
    int nine = 9;
    int ten = 10;        
}

public class Static
{
    static int one = 1;
    static int two = 2;
    static int three = 3;
    static int four = 4;
    static int five = 5;
    static int six = 6;
    static int seven = 7;
    static int eight = 8;
    static int nine = 9;
    static int ten = 10;
}

Потребление памяти сложно.Net, и я не буду притворяться, что понимаю его более тонкие детали, но если вы создадите список с миллионом "Static", он, вероятно, будет использовать значительно меньше памяти, чем если бы вы этого не сделали.

    static void Main(string[] args)
    {
        var maxSize = 1000000;
        var items = new List<NonStatic>();
        //var items = new List<Static>();

        for (var i=0;i<maxSize;i++)
        {
            items.Add(new NonStatic());
            //items.Add(new Static());
        }

        Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().WorkingSet64);
        Console.Read();
    }

При использовании "NonStatic" рабочий набор составляет 69 398 528 по сравнению с 32 423 936 при использовании статического электричества.

Ответ 6

Помимо небольшого улучшения производительности, когда вы объявляете константу, вы явно применяете два правила для себя и других разработчиков, которые будут использовать ваш код

  • Мне нужно инициализировать его со значением прямо сейчас, я не могу сделать это в другом месте.
  • Я не могу изменить его значение где угодно.

В коде все его читаемость и связь.

Ответ 7

Ключевое слово const указывает компилятору, что его можно полностью оценить во время компиляции. Для этого есть преимущество производительности и памяти, но оно мало.

Ответ 8

Константы в С# предоставляют имя с именем в памяти, чтобы сохранить значение данных. Это означает, что значение переменной будет известно во время компиляции и будет храниться в одном месте.

Когда вы объявляете его, он является "жестко запрограммированным" на промежуточном языке Microsoft (MSIL).

Хотя это немного, это может повысить производительность вашего кода. Если я объявляю переменную, и я могу сделать ее константой, я всегда это делаю. Не только потому, что он может улучшить производительность, но и потому, что идея констант. В противном случае, почему они существуют?

Отражатель может быть действительно полезен в таких ситуациях, как этот. Попробуйте объявить переменную, а затем сделайте ее константой и посмотрите, какой код генерируется в IL. Затем все, что вам нужно сделать, это увидеть разницу в инструкциях и посмотреть, что означают эти инструкции.