243

早些时候我问了一个问题,为什么我看到这么多示例使用var关键字并得到答案,虽然它只对匿名类型是必需的,但它仍然用于使编写代码“更快”/更容易和“只是因为”。

按照这个链接(“C# 3.0 - Var is not Objec”),我看到它var在 IL 中被编译为正确的类型(你将在文章的中途看到它)。

我的问题是,如果有的话,使用关键字的 IL 代码还需要多少,如果在任何地方都使用var它,它是否接近于代码性能的可测量水平?

4

12 回答 12

324

关键字没有额外的 IL 代码var:对于非匿名类型,生成的 IL 应该是相同的。如果编译器因为无法确定您打算使用的类型而无法创建该 IL,则会出现编译器错误。

唯一的技巧是,var如果您要手动设置类型,它将推断出您可能选择了接口或父类型的确切类型。

于 2008-12-10T17:21:40.507 回答
75

正如 Joel 所说,编译器在编译时计算出 var 应该是什么类型,实际上这只是编译器为保存击键而执行的一个技巧,例如

var s = "hi";

被取代

string s = "hi";

在生成任何 IL 之前由编译器执行。生成的 IL 将与您键入字符串完全相同。

于 2008-12-10T17:24:20.157 回答
30

由于还没有人提到反射器...

如果编译以下 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);
}

所以答案显然不会影响运行时性能!

于 2009-11-18T14:42:02.213 回答
17

对于以下方法:

   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
于 2011-02-22T20:15:20.613 回答
14

C# 编译器在编译时推断var变量的真实类型。生成的 IL 没有区别。

于 2008-12-10T17:23:28.943 回答
14

所以,要清楚,这是一种懒惰的编码风格。如果可以选择,我更喜欢原生类型;我将采取额外的“噪音”来确保我正在编写和阅读我认为我在代码/调试时的内容。*耸耸肩*

于 2015-08-20T15:29:44.593 回答
8

我认为你没有正确理解你所读的内容。如果它被编译为正确的类型,那么就没有区别。当我这样做时:

var i = 42;

编译器知道它是一个 int,并像我写的那样生成代码

int i = 42;

正如您链接到的帖子所说,它被编译为相同的类型。这不是运行时检查或其他任何需要额外代码的东西。编译器只是弄清楚类型必须是什么,并使用它。

于 2008-12-10T17:30:41.113 回答
5

使用 var 没有运行时性能成本。不过,我怀疑编译器需要推断类型时会产生编译性能成本,尽管这很可能可以忽略不计。

于 2008-12-10T17:41:10.450 回答
3

如果编译器可以进行自动类型推断,那么性能不会有任何问题。这两个都将生成相同的代码

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

但是,如果您正在动态构建类型(LINQ ...),那么var这是您唯一的问题,并且还有其他机制可以比较,以便说出什么是惩罚。

于 2008-12-10T17:28:33.863 回答
3

我总是在网络文章或指南文章中使用 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);
于 2014-07-21T01:55:18.803 回答
1

“var”是人们喜欢或讨厌的事物之一(例如区域)。但是,与区域不同,在创建匿名类时 var 是绝对必要的。

对我来说,当你直接新建一个对象时, var 是有意义的,例如:

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

话虽如此,您可以轻松地做到:

Dictionary<string, string> dict =new 和 intellisense 将在这里为您填写其余部分。

如果您只想使用特定接口,则不能使用 var ,除非您调用的方法直接返回该接口。

Resharper 似乎完全支持使用“var”,这可能会促使更多人这样做。但我有点同意,如果您正在调用一个方法,则更难阅读,而且名称返回的内容并不明显。

var 本身并不会减慢速度,但是有一个警告是很多人都没有想到的。如果你这样做var result = SomeMethod();了,那么之后的代码会期待某种结果,你会调用各种方法或属性或其他任何东西。如果SomeMethod()将其定义更改为其他类型,但仍符合其他代码所期望的约定,那么您只是创建了一个非常讨厌的错误(当然,如果没有单元/集成测试)。

于 2016-04-01T20:17:50.503 回答
0

这取决于情况,如果你尝试使用,下面的代码。

该表达式被转换为“OBJECT”并大大降低了性能,但这是一个孤立的问题。

代码:

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

问候

于 2019-05-24T00:25:06.073 回答