Будет ли использование "var" влиять на производительность?

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

После эта ссылка ( "С# 3.0 - Var Is Objec" ) Я увидел, что var скомпилирован до нужного типа в IL (вы увидите это примерно в середине статьи).

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

Ответ 1

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

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


Обновление через 8 лет

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

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. Но сказать, что это никогда не имеет никакого значения, может быть завышено.

Ответ 2

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

var s = "hi";

заменяется на

string s = "hi";

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

Ответ 3

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

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

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);
}

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

Ответ 4

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

   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

Ответ 5

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

Ответ 6

Компилятор С# регистрирует истинный тип переменной var во время компиляции. Нет никакой разницы в сгенерированном ИЛ.

Ответ 7

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

var i = 42;

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

int i = 42;

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

Ответ 8

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

Ответ 9

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

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

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

Ответ 10

Я всегда использую слово 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);

Ответ 11

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

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

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

Сказав это, вы можете легко сделать:

Dictionary<string, string> dict = новый и intellisense заполнит остальное для вас здесь.

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

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

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

Ответ 12

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

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

КОД:

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();
    }

С уважением