专栏首页.NET技术与企业级解决方案C#3.0新增功能03 隐式类型本地变量

C#3.0新增功能03 隐式类型本地变量

从 Visual C# 3.0 开始,在方法范围内声明的变量可以具有隐式“类型”var。 隐式类型本地变量为强类型,就像用户已经自行声明该类型,但编译器决定类型一样。 i 的以下两个声明在功能上是等效的:

var i = 10; // 隐式类型
int i = 10; // 显式类型

下面的示例演示两个查询表达式。 在第一个表达式中,var 的使用是允许的,但不是必需的,因为查询结果的类型可以明确表述为 IEnumerable<string>。 不过,在第二个表达式中,var 允许结果是一系列匿名类型,且相应类型的名称只可供编译器本身访问。 如果使用 var,便无法为结果新建类。 请注意,在示例 #2 中,foreach 迭代变量 item 必须也为隐式类型。

// 示例 #1: 当 select 子句指定字符串时,var是可选的
string[] words = { "apple", "strawberry", "grape", "peach", "banana" };
var wordQuery = from word in words
                where word[0] == 'g'
                select word;

// 因为序列中的每个元素都是字符串,而不是匿名类型,所以var在这里也是可选的。
foreach (string s in wordQuery)
{
    Console.WriteLine(s);
}

// 示例 #2: var 是必需的,因为select子句指定匿名类型
var custQuery = from cust in customers
                where cust.City == "Phoenix"
                select new { cust.Name, cust.Phone };

// 必须使用var,因为序列中的每个项都是匿名类型
foreach (var item in custQuery)
{
    Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);
}

隐式类型本地变量

可声明局部变量而无需提供显式类型。 var 关键字指示编译器通过初始化语句右侧的表达式推断变量的类型。 推断类型可以是内置类型、匿名类型、用户定义类型或 .NET Framework 类库中定义的类型。 有关如何使用 var 初始化数组的详细信息,请参阅隐式类型化数组

以下示例演示使用 var 声明局部变量的各种方式:

// i 被编译成 int 类型
var i = 5;

// s 被编译成 string 类型
var s = "Hello";

// a 被编译成 int[] 数组
var a = new[] { 0, 1, 2 };

// expr 被编译成 IEnumerable<Customer> 或者 IQueryable<Customer> 类型
var expr =
    from c in customers
    where c.City == "London"
    select c;

// anon 被编译成匿名类型
var anon = new { Name = "Terry", Age = 34 };

// list 被编译成 List<int> 集合                            
var list = new List<int>();

重要的是了解 var 关键字并不意味着“变体”,并且并不指示变量是松散类型或是后期绑定。 它只表示由编译器确定并分配最适合的类型。

在以下上下文中,可使用 var 关键字:

  • 在局部变量(在方法范围内声明的变量)上,如前面的示例所示。
  • for 初始化语句中
for(var x = 1; x < 10; x++)
foreach(var item in list){...}
using (var file = new StreamReader("C:\\myfile.txt")) {...}

有关详细信息,请参阅如何:在查询表达式中使用隐式类型本地变量和数组

var 和匿名类型

在许多情况下,使用 var 是可选的,只是一种语法便利。 但是,在使用匿名类型初始化变量时,如果需要在以后访问对象的属性,则必须将变量声明为 var。 这是 LINQ 查询表达式中的常见方案。 有关详细信息,请参阅匿名类型

从源代码角度来看,匿名类型没有名称。 因此,如果使用 var 初始化了查询变量,则访问返回对象序列中的属性的唯一方法是在 foreach 语句中将 var 用作迭代变量的类型。

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

        // 如果查询生成一系列匿名类型,则在foreach语句中使用var访问属性。
        var upperLowerWords =
             from w in words
             select new { Upper = w.ToUpper(), Lower = w.ToLower() };

        // 执行查询
        foreach (var ul in upperLowerWords)
        {
            Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper, ul.Lower);
        }
    }
}
/* 输出:
    Uppercase: APPLE, Lowercase: apple
    Uppercase: BLUEBERRY, Lowercase: blueberry
    Uppercase: CHERRY, Lowercase: cherry        
 */

特别说明

以下限制适用于隐式类型化变量声明:

  • 仅当局部变量在相同语句中进行声明和初始化时,才能使用 var;变量不能初始化为 null,也不能初始化为方法组或匿名函数。
  • var 不能在类范围内对字段使用。
  • 使用 var 声明的变量不能在初始化表达式中使用。 换句话说,此表达式是合法的: int i = (i = 20);,但是此表达式会生成编译时错误:var i = (i = 20);
  • 不能在相同语句中初始化多个隐式类型化变量。
  • 如果一种名为 var 的类型处于范围内,则 var 关键字会解析为该类型名称,不会被视为隐式类型化局部变量声明的一部分。

var 关键字的隐式类型只能应用于本地方法范围内的变量。 隐式类型不可用于类字段,因为 C# 编译器在处理代码时会遇到逻辑悖论:编译器需要知道字段的类型,但它在分析赋值表达式前无法确定类型,而表达式在不知道类型的情况下无法进行计算。 考虑下列代码:

private var bookTitles;

bookTitles 是类型为 var 的类字段。 由于该字段没有要计算的表达式,编译器无法推断出 bookTitles 应该是哪种类型。 此外,向该字段添加表达式(就像对本地变量执行的操作一样)也是不够的:

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

当编译器在代码编译期间遇到字段时,它会在处理与其关联的任何表达式之前记录每个字段的类型。 编译器在尝试分析 bookTitles 时遇到相同的悖论:它需要知道字段的类型,但编译器通常会通过分析表达式来确定 var 的类型,这在事先不知道类型的情况下无法实现。

你可能会发现,对于在其中难以确定查询变量的确切构造类型的查询表达式,var 也可能会十分有用。 这可能会针对分组和排序操作发生。

当变量的特定类型在键盘上键入时很繁琐、或是显而易见、或是不会提高代码的可读性时,var 关键字也可能非常有用。 var 采用此方法提供帮助的一个示例是针对嵌套泛型类型(如用于分组操作的类型)。 在下面的查询中,查询变量的类型是 IEnumerable<IGrouping<string, Student>>。 只要你和必须维护你的代码的其他人了解这一点,使用隐式类型化实现便利性和简便性时便不会出现问题。

// 与前面的示例相同,只是我们使用整个姓氏作为键。
// 查询变量是IEnumerable<igrouping<string,student>>
var studentQuery3 =
    from student in students
    group student by student.Last;

但是,使用 var 至少有可能使代码对其他开发人员更加难以理解。 为此,C# 文档通常只在需要时才使用 var

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • xBIM 基础15 IFC导出Excel报表

      本篇将向您展示从IFC文件读取数据所需的一些概念。它使用IFC4接口,适用于IFC2x3和IFC4型号。要创建Excel文件,我们使用NPOI。在这个例子中...

    张传宁老师
  • xBIM 实战03 使用WPF技术实现IFC模型的加载与浏览

      WPF应用程序在底层使用 DirectX ,无论设计复杂的3D图形(这是 DirectX 的特长所在)还是绘制简单的按钮与文本,所有绘图工作都是通过 Dir...

    张传宁老师
  • xBIM 基础02 快速入门

      Visual Studio 新建项目、项目创建完成后 Nuget ,项目添加 Xbim.Essentials,那么如果项目需要几何引擎还需要集成 Xbim....

    张传宁老师
  • MariaDB MySQL变量取值避免四舍五入的方法

    在一些对数据精确度要求比较高的场景(比如资金结算)下,变量取值时不能对变量值进行四舍五入操作,这时候就要做些预处理工作。

    授客
  • 如何防止网站被扒的解决方法!

    这个代码能够直接保护整个站,而不再是单个页面,直接把代码放到自己的网站上,如果是博客建议放到header.php头部文件,如果是单页面直接放到首页即可!

    空木白博客
  • mapboxGL之风流图

    前面的文章说到了Openlayers4中风场的实现,本文将讲述如何在mapbox GL实现类似的效果。

    lzugis
  • Nodejs进阶:Express常用中间件body-parser实现解析

    写在前面 body-parser是非常常用的一个express中间件,作用是对post请求的请求体进行解析。使用非常简单,以下两行代码已经覆盖了大部分的使用场景...

    IMWeb前端团队
  • ThingJS结合Web地图API开发,让数据展示更加出色!

    三维地图,是为了更好的数据可视化,以便更好地进行数据分析。ThingJS结合Web地图API开发了更多3D功能,让数据展示更加出色!

    森友鹿锘
  • linux 磁盘占满 查看占用

    参考https://blog.csdn.net/ithomer/article/details/89530790 查看某个目录的文件大小并排序(单位为MB)....

    平凡的学生族
  • 在 Silverlight 5 项目中使用 async/await

    .Net 4.5 提供了 async/await 让异步编程回归同步, 不过, async/await 不是只能在 .Net 4.5 下才能使用, 通过使用 A...

    beginor

扫码关注云+社区

领取腾讯云代金券