代码之家  ›  专栏  ›  技术社区  ›  Joel Etherton

在C中,使用var的推断变量在内存和生命周期方面的行为如何?

  •  3
  • Joel Etherton  · 技术社区  · 14 年前

    好的,我已经阅读了我能在var上找到的所有东西,我确信我已经掌握了它们的基本行为和类型推断。我一直都是显式类型的支持者,所以当我阅读代码时,var让我有点急躁。所以我有几个问题,关于它的内存使用,以及在变量在内存中的生命周期中用var声明的变量的行为。

    因为var是对显式或匿名类型的推理,所以它的内存将被分配到同一个位置吗?它的对应类型将是var,或者是var,在堆上被普遍创建并被访问,就像它是一个对象一样。举个例子:

    int i = 5;  // puts this on the stack
    var i = 5;  // does this also go on the stack?
    

    声明的var在初始化后是否具有常量类型,或者也可以调整它?我问这个是因为我在指定这个的文档中找不到,我只是在 this SO question 通过 @Eric Lippert :

    变量是一个存储位置,其 内容变化

    在测试了以下代码之后,我甚至在IDE级别上也看到了一个隐式转换异常。我在这一点上没有使用Linq的经验,无法对匿名类型运行类似的测试。他们也有同样的行为吗?IDE是否会在设计时识别出类型不匹配,或者此类代码是否会收到运行时异常?

    var i = 5;    // Initializes as int, value is 5
    i = "Steve";  // Type casting error
    

    最后,是否存在这样一种情况,即在设计时您可能知道某个类型,但无论如何使用var都是明智的?我问是因为我看到过代码示例,人们在哪里这样做,从我读到的内容来看,它让我觉得只是懒惰的编码。

    编辑:我知道有很多关于这个主题的文章,但是我没有找到任何专门回答这些问题的文章(尽管有一些提示)。我很乐意阅读您认为与这些主题相关的任何文档,请发布链接。

    5 回复  |  直到 13 年前
        1
  •  17
  •   Adam Robinson    14 年前

    var 是C编译器中的100%句法糖。生成实际IL时,将显式定义类型。 var -声明变量的行为与其显式定义的对应变量没有任何不同。你所看到的缺乏信息是由于 var 比你想象的简单。这两行字面上没有区别:

    var i = 10;
    int j = 10;
    

    (除了你看到单词 var int 当然,它们在功能上完全相同)。

        2
  •  9
  •   Coding Flow    13 年前

    var变量由编译器推断,它们实际上只是语法上的糖分,两者之间没有区别:

    var i =0;
    

    int i = 0;
    

    在编译的代码中。

    添加它们的目的是允许匿名类型,例如

    var MyVar = new { prop1="A string", prop2=5};
    

    是的,var变量在编译时识别出类型不匹配,编译器在编译时动态地为它们创建一个类。例如,以下内容无法编译:

    var MyVar = new { prop1="A string", prop2=5};
    MyVar = "Fred";
    
        3
  •  4
  •   Jon Skeet    14 年前

    正如其他人所说, var 对变量在内存中的行为没有影响-这只是意味着您没有指定名称。对于匿名类型, 不能 指定名称,首先是因为您在编译时不知道它,其次是因为这些名称故意“无法说”——它们在C中无效。(通常包含 <> 比如说)

    为代码生成的IL使用 var 使用显式名称的代码是 确切地 相同的。正如普通变量不能更改类型一样,也不能使用 var …所以在您的示例中,您试图将值“steve”赋给一个隐式类型为 int ,您将得到一个编译时错误,就像 明确地 声明为类型 int .

    至于何时使用 var 如果不这样做,我有一些经验法则:

    • 显然,如果您希望变量的类型不是所分配表达式的编译时类型,则必须显式地执行该操作。
    • 对于构造函数调用,即使使用 var
    • var 有助于强调 什么 代码是用来做而不是 怎样
    • 我经常使用 var 如果显式名称非常长,特别是对于具有多个类型参数的泛型。

    基本上都是关于可读性的:如果代码更容易用 var 去吧。如果没有,不要。注意这个 不是 与保存键入内容相同…代码通常比写的要读得多,所以想想你的读者吧。埃里克·利珀特写了一篇伟大的 note 当技术人员对第一版C进行深入审查时,值得一读。

        4
  •  3
  •   Noldorin    14 年前

    简单的回答:与正常变量完全相同。

    var 声明在编译时转换为特定(强)类型。 var 只是一种自动类型推断的方法,与动态语言无关。归根结底,这只是编译器的聪明和翻译 var 输入您想要的实际类型。

        5
  •  1
  •   Matthew Abbott    14 年前

    由于var是对显式类型或匿名类型的推理,它的内存将被分配到相同的位置吗?它的对应类型将是var,或是var,在堆上被普遍创建并被访问,就像它是一个对象一样。

    关于var,重要的是编译器在编译时将var语句更改为实际类型,因此:

    var number = 1;
    

    将更改为:

    System.Int32 number = 1;
    

    …由编译器编写。因此,存储这些类型的内存位置也没有什么不同。var本质上是句法上的糖。因此,值类型的方法局部声明将存储在堆栈上,引用指针将存储在堆栈上,引用对象位于堆栈上。

    一旦您将变量声明为var,因为编译器会将其转换为完整的类型,所以您就不能动态地更改类型:

    var i = 5;
    i = "Steve"; 
    

    …无效,因为它已声明为Int32。

    匿名类型遵循类似的行为,即编译器在编译期间创建类型。

    “最后,有没有一种情况,您可以考虑在设计时在哪里知道一种类型,但无论如何使用var都是明智的?”

    就我个人而言,我遵循一个简单的模式:

    对于原语,我总是将类型:

    int i = 5;
    string name = "Matt";
    

    对于复杂类型,我主要这样做:

    var instance = new MyComplexTypeInstance();
    

    对于LINQ结果,我坚持使用var:

    var result = from i in something select i;
    

    对于方法,如果方法描述了返回的类型,那么我将使用var。

    var instance = GetInstance();
    

    然而,更复杂的方法名称,我会将实际类型:

    Result result = DoSomethingWeirdAndWonderful(); 
    

    每个开发人员都会找到他们喜欢的东西,选择权属于你。因为var实际上只是一个设计时的东西,它的所有句法糖分。