隐式类型本地变量(C# 编程指南)Implicitly typed local variables (C# Programming Guide)

可声明局部变量而无需提供显式类型。Local variables can be declared without giving an explicit type. var 关键字指示编译器通过初始化语句右侧的表达式推断变量的类型。The var keyword instructs the compiler to infer the type of the variable from the expression on the right side of the initialization statement. 推断类型可以是内置类型、匿名类型、用户定义类型或 .NET Framework 类库中定义的类型。The inferred type may be a built-in type, an anonymous type, a user-defined type, or a type defined in the .NET Framework class library. 有关如何使用 var 初始化数组的详细信息,请参阅隐式类型化数组For more information about how to initialize arrays with var, see Implicitly Typed Arrays.

以下示例演示使用 var 声明局部变量的各种方式:The following examples show various ways in which local variables can be declared with var:

// i is compiled as an int
var i = 5;

// s is compiled as a string
var s = "Hello";

// a is compiled as int[]
var a = new[] { 0, 1, 2 };

// expr is compiled as IEnumerable<Customer>
// or perhaps IQueryable<Customer>
var expr =
    from c in customers
    where c.City == "London"
    select c;

// anon is compiled as an anonymous type
var anon = new { Name = "Terry", Age = 34 };

// list is compiled as List<int>                             
var list = new List<int>();

重要的是了解 var 关键字并不意味着“变体”,并且并不指示变量是松散类型或是后期绑定。It is important to understand that the var keyword does not mean "variant" and does not indicate that the variable is loosely typed, or late-bound. 它只表示由编译器确定并分配最适合的类型。It just means that the compiler determines and assigns the most appropriate type.

在以下上下文中,可使用 var 关键字:The var keyword may be used in the following contexts:

  • 在局部变量(在方法范围内声明的变量)上,如前面的示例所示。On local variables (variables declared at method scope) as shown in the previous example.

  • for 初始化语句中。In a for initialization statement.

    for(var x = 1; x < 10; x++)
    
  • foreach 初始化语句中。In a foreach initialization statement.

    foreach(var item in list){...}
    
  • using 域间中。In a using statement.

    using (var file = new StreamReader("C:\\myfile.txt")) {...}
    

有关详细信息,请参阅如何:在查询表达式中使用隐式类型本地变量和数组For more information, see How to: Use Implicitly Typed Local Variables and Arrays in a Query Expression.

var 和匿名类型var and anonymous types

在许多情况下,使用 var 是可选的,只是一种语法便利。In many cases the use of var is optional and is just a syntactic convenience. 但是,在使用匿名类型初始化变量时,如果需要在以后访问对象的属性,则必须将变量声明为 varHowever, when a variable is initialized with an anonymous type you must declare the variable as var if you need to access the properties of the object at a later point. 这是 LINQLINQ 查询表达式中的常见方案。This is a common scenario in LINQLINQ query expressions. 有关详细信息,请参阅匿名类型For more information, see Anonymous Types.

从源代码角度来看,匿名类型没有名称。From the perspective of your source code, an anonymous type has no name. 因此,如果使用 var 初始化了查询变量,则访问返回对象序列中的属性的唯一方法是在 foreach 语句中将 var 用作迭代变量的类型。Therefore, if a query variable has been initialized with var, then the only way to access the properties in the returned sequence of objects is to use var as the type of the iteration variable in the foreach statement.

class ImplicitlyTypedLocals2
{
    static void Main()
    {
        string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };

        // If a query produces a sequence of anonymous types, 
        // then use var in the foreach statement to access the properties.
        var upperLowerWords =
             from w in words
             select new { Upper = w.ToUpper(), Lower = w.ToLower() };

        // Execute the query
        foreach (var ul in upperLowerWords)
        {
            Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper, ul.Lower);
        }
    }
}
/* Outputs:
    Uppercase: APPLE, Lowercase: apple
    Uppercase: BLUEBERRY, Lowercase: blueberry
    Uppercase: CHERRY, Lowercase: cherry        
 */

备注Remarks

以下限制适用于隐式类型化变量声明:The following restrictions apply to implicitly-typed variable declarations:

  • 仅当局部变量在相同语句中进行声明和初始化时,才能使用 var;变量不能初始化为 null,也不能初始化为方法组或匿名函数。var can only be used when a local variable is declared and initialized in the same statement; the variable cannot be initialized to null, or to a method group or an anonymous function.

  • var 不能在类范围内对字段使用。var cannot be used on fields at class scope.

  • 使用 var 声明的变量不能在初始化表达式中使用。Variables declared by using var cannot be used in the initialization expression. 换句话说,此表达式是合法的: int i = (i = 20);,但是此表达式会生成编译时错误:var i = (i = 20);In other words, this expression is legal: int i = (i = 20); but this expression produces a compile-time error: var i = (i = 20);

  • 不能在相同语句中初始化多个隐式类型化变量。Multiple implicitly-typed variables cannot be initialized in the same statement.

  • 如果一种名为 var 的类型处于范围内,则 var 关键字会解析为该类型名称,不会被视为隐式类型化局部变量声明的一部分。If a type named var is in scope, then the var keyword will resolve to that type name and will not be treated as part of an implicitly typed local variable declaration.

var 关键字的隐式类型只能应用于本地方法范围内的变量。Implicit typing with the var keyword can only be applied to variables at local method scope. 隐式类型不可用于类字段,因为 C# 编译器在处理代码时会遇到逻辑悖论:编译器需要知道字段的类型,但它在分析赋值表达式前无法确定类型,而表达式在不知道类型的情况下无法进行计算。Implicit typing is not available for class fields as the C# compiler would encounter a logical paradox as it processed the code: the compiler needs to know the type of the field, but it cannot determine the type until the assignment expression is analyzed, and the expression cannot be evaluated without knowing the type. 考虑下列代码:Consider the following code:

private var bookTitles;

bookTitles 是类型为 var 的类字段。bookTitles is a class field given the type var. 由于该字段没有要计算的表达式,编译器无法推断出 bookTitles 应该是哪种类型。As the field has no expression to evaluate, it is impossible for the compiler to infer what type bookTitles is supposed to be. 此外,向该字段添加表达式(就像对本地变量执行的操作一样)也是不够的:In addition, adding an expression to the field (like you would for a local variable) is also insufficient:

private var bookTitles = new List<string>();

当编译器在代码编译期间遇到字段时,它会在处理与其关联的任何表达式之前记录每个字段的类型。When the compiler encounters fields during code compilation, it records each field's type before processing any expressions associated with it. 编译器在尝试分析 bookTitles 时遇到相同的悖论:它需要知道字段的类型,但编译器通常会通过分析表达式来确定 var 的类型,这在事先不知道类型的情况下无法实现。The compiler encounters the same paradox trying to parse bookTitles: it needs to know the type of the field, but the compiler would normally determine var's type by analyzing the expression, which isn't possible without knowing the type beforehand.

你可能会发现,对于在其中难以确定查询变量的确切构造类型的查询表达式,var 也可能会十分有用。You may find that var can also be useful with query expressions in which the exact constructed type of the query variable is difficult to determine. 这可能会针对分组和排序操作发生。This can occur with grouping and ordering operations.

当变量的特定类型在键盘上键入时很繁琐、或是显而易见、或是不会提高代码的可读性时,var 关键字也可能非常有用。The var keyword can also be useful when the specific type of the variable is tedious to type on the keyboard, or is obvious, or does not add to the readability of the code. var 采用此方法提供帮助的一个示例是针对嵌套泛型类型(如用于分组操作的类型)。One example where var is helpful in this manner is with nested generic types such as those used with group operations. 在下面的查询中,查询变量的类型是 IEnumerable<IGrouping<string, Student>>In the following query, the type of the query variable is IEnumerable<IGrouping<string, Student>>. 只要你和必须维护你的代码的其他人了解这一点,使用隐式类型化实现便利性和简便性时便不会出现问题。As long as you and others who must maintain your code understand this, there is no problem with using implicit typing for convenience and brevity.

// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
var studentQuery3 =
    from student in students
    group student by student.Last;

但是,使用 var 至少有可能使代码对其他开发人员更加难以理解。However, the use of var does have at least the potential to make your code more difficult to understand for other developers. 为此,C# 文档通常只在需要时才使用 varFor that reason, the C# documentation generally uses var only when it is required.

请参阅See also