Повлияет ли использование 'var' на производительность?

Ранее я задал вопрос о том, почему я вижу, что во многих примерах используется varключевое слово, и получил ответ, что, хотя это необходимо только для анонимных типов, оно, тем не менее, используется для того, чтобы сделать написание кода «быстрее» / проще и «просто потому что».

По этой ссылке («C # 3.0 - Var Is Not Objec») я увидел, что он varскомпилирован в правильный тип в IL (вы увидите его в середине статьи).

Мой вопрос состоит в том, насколько больше, если таковой имеется, IL-кода использует varключевое слово take, и будет ли оно даже близко к измеряемому уровню производительности кода, если бы он использовался повсеместно?

10.12.2008 17:19:45
На вопрос, на который давным-давно ответили, я просто хотел добавить еще одну вещь к var - несмотря на то, что он был решен во время компиляции, он не обнаружен должным образом в «Найти все ссылки» в Visual Studio и в «Найти использование» в Resharper, если вы хотите найти все использования типа - и это не будет исправлено, потому что это будет слишком медленно.
KolA 2.11.2015 22:01:48
@KolA Переменные, объявленные varнаиболее точно, работают с «Find All References» в Visual Studio 2019, поэтому, если он когда-либо был сломан, он был исправлен. Но я могу подтвердить, что он работает еще в Visual Studio 2012, поэтому я не уверен, почему вы утверждали, что он не работает.
Herohtar 30.11.2019 09:09:59
@Herohtar попробуйте следующий код "class X {} X GetX () {return new X ();} void UseX () {var x = GetX ();}" и найдите все ссылки на X, "var x = GetX ( ) "немного не выделено - в последней VS2019 на данный момент это то, что я имел в виду. Это будет выделено, хотя, если вы используете «X x = GetX ()» вместо var
KolA 5.12.2019 22:48:07
@KolA Ах, я понимаю, что вы имеете в виду - varне будет считаться ссылкой, Xкогда вы используете "Найти все ссылки" на X. Интересно, что если вы используете «Найти все ссылки» на varв этом заявлении, он будет показывать вам ссылки X(хотя он все еще не перечислит varзаявление). Кроме того, когда курсор включен var, он будет выделять все экземпляры Xв одном и том же документе (и наоборот).
Herohtar 5.12.2019 23:06:09
12 ОТВЕТОВ
РЕШЕНИЕ

Для varключевого слова нет дополнительного кода IL : полученный IL должен быть идентичным для неанонимных типов. Если компилятор не может создать этот IL, потому что он не может определить, какой тип вы намеревались использовать, вы получите ошибку компилятора.

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


Обновление 8 лет спустя

Мне нужно обновить это, так как мое понимание изменилось. Теперь я считаю, что это может varповлиять на производительность в ситуации, когда метод возвращает интерфейс, но вы бы использовали точный тип. Например, если у вас есть этот метод:

IList<int> Foo()
{
    return Enumerable.Range(0,10).ToList();
}

Рассмотрим эти три строки кода для вызова метода:

List<int> bar1 = Foo();
IList<int> bar = Foo();
var bar3 = Foo();

Все три компилируются и выполняются, как и ожидалось. Однако первые две строки не совсем совпадают, а третья строка будет соответствовать второй, а не первой. Поскольку сигнатура Foo()должна возвращать IList<int>, именно так компилятор будет создавать bar3переменную.

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

Обратите внимание, что возможно (вероятно, даже) джиттер сможет стереть эту разницу, но это не гарантировано. Как правило, вы все равно должны считаться varне фактором с точки зрения производительности. Это, конечно, совсем не похоже на использование dynamicпеременной. Но сказать, что это никогда ничего не меняет, может быть преувеличивать.

312
23.05.2017 12:03:03
Необходимо не только IL быть идентичны - это является идентичным. var i = 42; компилируется в точно такой же код, как int i = 42;
Brian Rasmussen 10.12.2008 18:58:15
@BrianRasmussen: я знаю, что ваш пост старый, но я предполагаю var i = 42;(вывод типа int) НЕ идентичен long i = 42;. Так что в некоторых случаях вы можете делать неверные предположения о выводе типа. Это может вызвать неуловимые / крайние ошибки времени выполнения, если значение не подходит. По этой причине, все еще может быть хорошей идеей быть явным, если значение не имеет явного типа. Так, например, var x = new List<List<Dictionary<int, string>()>()>()было бы приемлемо, но var x = 42несколько двусмысленно и должно быть записано как int x = 42. Но каждому свое ...
Nelson Rothermel 9.05.2012 17:26:31
@NelsonRothermel: var x = 42; не является двусмысленным. Целочисленные литералы имеют тип int. Если хочешь буквально долго пиши var x = 42L;.
Brian Rasmussen 9.05.2012 18:47:56
Хм, что означает IL в C #? Я никогда не слышал об этом.
puretppc 19.01.2014 20:08:27
В вашем примере из 3 строк кода, которые ведут себя по-разному, первая строка не компилируется . Вторая и третья строки, которые и делают обобщать, делать то же самое. Если Fooвозвращается a List, а не an IList, тогда все три строки будут компилироваться, но третья строка будет вести себя как первая строка , а не вторая.
Servy 17.11.2016 21:48:46

Компилятор C # определяет истинный тип varпеременной во время компиляции. Там нет разницы в сгенерированном IL.

14
10.12.2008 17:23:28

Как говорит Джоэл, компилятор работает при компиляции , что должно быть тип вар, эффективно это просто трюк выполняет компилятор , чтобы сохранить нажатия клавиш, так, например ,

var s = "hi";

заменяется

string s = "hi";

компилятором до того, как будет сгенерирован любой IL. Сгенерированный IL будет точно таким же, как если бы вы набрали строку.

72
24.06.2011 07:54:26

Если компилятор может делать автоматическое определение типа, то с производительностью проблем не будет. Оба из них будут генерировать один и тот же код

var    x = new ClassA();
ClassA x = new ClassA();

однако, если вы создаете тип динамически (LINQ ...), тогда varэто ваш единственный вопрос, и есть другой механизм, с которым можно сравнить, чтобы сказать, каков штраф.

3
24.06.2011 07:54:32

Я не думаю, что вы правильно поняли, что вы читаете. Если он компилируется к правильному типу, то нет никакой разницы. Когда я делаю это:

var i = 42;

Компилятор знает, что это int, и генерирует код, как если бы я написал

int i = 42;

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

8
10.12.2008 17:30:41
Правильно, но что если позже вы i = i - someVar и someVar = 3.3. я сейчас Инт Лучше быть явным, чтобы не только дать компилятору преимущество при поиске недостатков, но и чтобы минимизировать ошибки во время выполнения или замедляющие преобразование типов. * пожимает плечами * Это также делает код лучше для самоописания. Я делал это очень долго. Я буду брать «зашумленный» код с явными типами каждый раз, если есть возможность выбора.
ChrisH 31.03.2019 19:07:20

Нет никаких затрат производительности при использовании var. Хотя я подозреваю, что производительность компиляции будет снижена, поскольку компилятор должен определить тип, хотя это, скорее всего, будет незначительным.

5
10.12.2008 17:41:10
в любом случае RHS должен рассчитывать свой тип - компилятор будет отлавливать несовпадающие типы и выдавать ошибку, так что я думаю, что это не слишком дорого.
Jimmy 10.12.2008 17:47:20

Как никто еще не упомянул отражатель ...

Если вы компилируете следующий код C #:

static void Main(string[] args)
{
    var x = "hello";
    string y = "hello again!";
    Console.WriteLine(x);
    Console.WriteLine(y);
}

Затем, используя отражатель, вы получите:

// Methods
private static void Main(string[] args)
{
    string x = "hello";
    string y = "hello again!";
    Console.WriteLine(x);
    Console.WriteLine(y);
}

Таким образом, ответ явно не влияет на производительность во время выполнения!

26
2.05.2017 11:21:07

Для следующего метода:

   private static void StringVsVarILOutput()
    {
        var string1 = new String(new char[9]);

        string string2 = new String(new char[9]);
    }

Выход IL это:

        {
          .method private hidebysig static void  StringVsVarILOutput() cil managed
          // Code size       28 (0x1c)
          .maxstack  2
          .locals init ([0] string string1,
                   [1] string string2)
          IL_0000:  nop
          IL_0001:  ldc.i4.s   9
          IL_0003:  newarr     [mscorlib]System.Char
          IL_0008:  newobj     instance void [mscorlib]System.String::.ctor(char[])
          IL_000d:  stloc.0
          IL_000e:  ldc.i4.s   9
          IL_0010:  newarr     [mscorlib]System.Char
          IL_0015:  newobj     instance void [mscorlib]System.String::.ctor(char[])
          IL_001a:  stloc.1
          IL_001b:  ret
        } // end of method Program::StringVsVarILOutput
17
22.02.2011 20:15:20

Я всегда использую слово var в веб-статьях или руководствах.

Ширина текстового редактора онлайн-статьи невелика.

Если я напишу это:

SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();

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

Вот почему я всегда использую ключевое слово var в записях веб-статей.

var coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();

Весь представленный предварительный код просто помещается на экране.

На практике для объявления объекта я редко использую var, я полагаюсь на intellisense для более быстрого объявления объекта.

Пример:

SomeCoolNamespace.SomeCoolObject coolObject = new SomeCoolNamespace.SomeCoolObject();

Но для возврата объекта из метода я использую var, чтобы быстрее написать код.

Пример:

var coolObject = GetCoolObject(param1, param2);
3
17.02.2016 01:59:00
Если вы пишете для студентов, то ешьте свою собачью еду и всегда пишите ее одинаково «правильно», последовательно. Студенты часто воспринимают вещи на 100% дословно и начинают использовать любые небрежные привычки, которые они приобретают по пути. $ .02
ChrisH 20.11.2017 23:05:01

Итак, чтобы быть ясным, это ленивый стиль кодирования. Я предпочитаю нативные типы, учитывая выбор; Я возьму этот лишний «шум», чтобы убедиться, что я пишу и читаю именно то, что, как мне кажется, находится во время кода / отладки. * пожимает плечами *

14
20.08.2015 15:29:44
Это только ваш субъективный взгляд, а не ответ на вопрос о производительности. Правильный ответ - это не влияет на производительность. Я голосовал за близких
Anders 31.03.2019 09:57:27
Это не отвечает на вопрос, varвлияет ли это на производительность вообще; Вы просто высказываете свое мнение о том, должны ли люди его использовать.
Herohtar 30.11.2019 08:59:55
Например, вывод типа из значения позже, переключение с int 5 на float 5.25, может привести к проблемам с производительностью. *
ChrisH 1.12.2019 14:52:47
Нет, это не вызовет проблем с производительностью; вы будете получать ошибки сборки в любых местах, где ожидалась переменная типа, intпотому что она не может автоматически преобразовать float, но это точно то же самое, что произошло бы, если вы явно использовали intи затем изменили на float. В любом случае, ваш ответ по-прежнему не отвечает на вопрос " varвлияет ли использование на производительность?" (особенно с точки зрения сгенерированного IL)
Herohtar 5.12.2019 22:56:13

«var» - это одна из тех вещей, которые люди либо любят, либо ненавидят (например, регионы). Хотя, в отличие от регионов, var абсолютно необходим при создании анонимных классов.

Для меня var имеет смысл, когда вы обновляете объект напрямую, например:

var dict = new Dictionary<string, string>();

При этом, вы можете легко сделать:

Dictionary<string, string> dict = new и intellisense заменит вам все остальное здесь.

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

Resharper, кажется, на стороне использования «var» повсюду, что может подтолкнуть больше людей, чтобы сделать это таким образом. Но я согласен, что читать сложнее, если вы вызываете метод, и неясно, что возвращает имя.

Сам по себе var не тормозит, но есть одна оговорка, о которой не многие думают. Если вы это сделаете, var result = SomeMethod();то код после этого ожидает некоторого результата назад, где вы будете вызывать различные методы или свойства или что-то еще. Если вы SomeMethod()изменили свое определение на какой-то другой тип, но все равно выполнили контракт, которого ожидал другой код, вы просто создали действительно неприятную ошибку (если, конечно, нет модульных / интеграционных тестов).

1
1.04.2016 20:17:50

Это зависит от ситуации, если вы попробуете использовать этот код ниже.

Выражение преобразуется в «ОБЪЕКТ» и сильно снижает производительность, но это отдельная проблема.

КОД:

public class Fruta
{
    dynamic _instance;

    public Fruta(dynamic obj)
    {
        _instance = obj;
    }

    public dynamic GetInstance()
    {
        return _instance;
    }
}

public class Manga
{
    public int MyProperty { get; set; }
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
    public int MyProperty3 { get; set; }
}

public class Pera
{
    public int MyProperty { get; set; }
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
}

public class Executa
{
    public string Exec(int count, int value)
    {
        int x = 0;
        Random random = new Random();
        Stopwatch time = new Stopwatch();
        time.Start();

        while (x < count)
        {
            if (value == 0)
            {
                var obj = new Pera();
            }
            else if (value == 1)
            {
                Pera obj = new Pera();
            }
            else if (value == 2)
            {
                var obj = new Banana();
            }
            else if (value == 3)
            {
                var obj = (0 == random.Next(0, 1) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance());
            }
            else
            {
                Banana obj = new Banana();
            }

            x++;
        }

        time.Stop();
        return time.Elapsed.ToString();
    }

    public void ExecManga()
    {
        var obj = new Fruta(new Manga()).GetInstance();
        Manga obj2 = obj;
    }

    public void ExecPera()
    {
        var obj = new Fruta(new Pera()).GetInstance();
        Pera obj2 = obj;
    }
}

Выше результатов с ILSPY.

public string Exec(int count, int value)
{
    int x = 0;
    Random random = new Random();
    Stopwatch time = new Stopwatch();
    time.Start();

    for (; x < count; x++)
    {
        switch (value)
        {
            case 0:
                {
                    Pera obj5 = new Pera();
                    break;
                }
            case 1:
                {
                    Pera obj4 = new Pera();
                    break;
                }
            case 2:
                {
                    Banana obj3 = default(Banana);
                    break;
                }
            case 3:
                {
                    object obj2 = (random.Next(0, 1) == 0) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance();
                    break;
                }
            default:
                {
                    Banana obj = default(Banana);
                    break;
                }
        }
    }
time.Stop();
return time.Elapsed.ToString();
}

Если вы хотите выполнить этот код, используйте приведенный ниже код и получите разницу во времени.

        static void Main(string[] args)
    {
        Executa exec = new Executa();            
        int x = 0;
        int times = 4;
        int count = 100000000;
        int[] intanceType = new int[4] { 0, 1, 2, 3 };

        while(x < times)
        {                
            Parallel.For(0, intanceType.Length, (i) => {
                Console.WriteLine($"Tentativa:{x} Tipo de Instancia: {intanceType[i]} Tempo Execução: {exec.Exec(count, intanceType[i])}");
            });
            x++;
        }

        Console.ReadLine();
    }

С уважением

0
24.05.2019 01:00:28