C#3.0新增功能03 隐式类型本地变量
var i = ; // 隐式类型
int i = ; // 显式类型
下面的示例演示两个查询表达式。 在第一个表达式中,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[] == '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 = ; // s 被编译成 string 类型
var s = "Hello"; // a 被编译成 int[] 数组
var a = new[] { , , }; // expr 被编译成 IEnumerable<Customer> 或者 IQueryable<Customer> 类型
var expr =
from c in customers
where c.City == "London"
select c; // anon 被编译成匿名类型
var anon = new { Name = "Terry", Age = }; // list 被编译成 List<int> 集合
var list = new List<int>();
重要的是了解 var
关键字并不意味着“变体”,并且并不指示变量是松散类型或是后期绑定。 它只表示由编译器确定并分配最适合的类型。
在以下上下文中,可使用 var
关键字:
在局部变量(在方法范围内声明的变量)上,如前面的示例所示。
在 for 初始化语句中
for(var x = ; x < ; x++)
- 在 foreach 初始化语句中
foreach(var item in list){...}
- 在 using 域间中
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
。
其他技术请参阅
C#3.0新增功能03 隐式类型本地变量的更多相关文章
- C#中隐式类型本地变量var
在新接触的项目中,看到很多声明变量时用var.只记得在javascript中声明变量用var.今天在家里看C#和.Net高级编程,看到隐式变量这一块,就总结一下C# 中隐式变量var的用法. 1.C# ...
- C#2.0新增功能03 匿名方法
连载目录 [已更新最新开发文章,点击查看详细] 在 2.0 之前的 C# 版本中,声明委托的唯一方式是使用命名方法. C# 2.0 引入匿名方法,在 C# 3.0 及更高版本中,Lambda 表 ...
- C#4.0新增功能03 泛型中的协变和逆变
连载目录 [已更新最新开发文章,点击查看详细] 协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更小(不太具体 ...
- C#3.0新增功能02 匿名类型
连载目录 [已更新最新开发文章,点击查看详细] 匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型. 类型名由编译器生成,并且不能在源代码级使用. 每 ...
- Linq之隐式类型、自动属性、初始化器、匿名类
目录 写在前面 系列文章 隐式类型 自动属性 初始化器 匿名类 总结 写在前面 上篇文章是本系列的小插曲,也是在项目中遇到,觉得有必要总结一下,就顺手写在了博客中,也希望能帮到一些朋友.本文将继续介绍 ...
- C#2.0新增功能06 协变和逆变
连载目录 [已更新最新开发文章,点击查看详细] 在 C# 中,协变和逆变能够实现数组类型.委托类型和泛型类型参数的隐式引用转换. 协变保留分配兼容性,逆变则与之相反. 以下代码演示分配兼容性.协 ...
- C#3.0新增功能09 LINQ 基础03 LINQ 和泛型类型
连载目录 [已更新最新开发文章,点击查看详细] LINQ 查询基于 .NET Framework 版本 2.0 中引入的泛型类型. 无需深入了解泛型即可开始编写查询. 但是,可能需要了解 2 个 ...
- C#7.0 新增功能
连载目录 [已更新最新开发文章,点击查看详细] C# 7.0 向 C# 语言添加了许多新功能 01 out 变量 支持 out 参数的现有语法已在此版本中得到改进. 现在可以在方法调用的参数列表 ...
- C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数
一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...
随机推荐
- FireUI live Preview使用方法-Berlin
这是可以让开发者事先预览 mobile 画面的作法 1.先确定 Berlin IDE Tools\Option\Form Designer 中 FireUI live Preview broad ...
- 80%的岗位是没有太多能力上的要求的(少部分聪明的人开始觉醒,这部分一定是那些主动追求、主动学习的人;30岁现象能区分真正专业和不学无术的人)good
不要沦陷程序员的30岁问题 热门> 就是学习能力和工作热情态度的问题. 我之前也跟作者一样思考过这个问题,答案是否定的. 在知识积累的行业,年纪越大,越吃香,比如金融,医学,IT.就怕3 ...
- delphi中pos和Ansipos函数的区别
POS和ANSIPOS的主要区别在于,POS参数多用于是一个字符,而ANSIPOS多用于是多个字符: 例如:i:=pos('a','sssssas'); i:=ansipos('abc','sdabc ...
- 八大排序算法 JAVA实现 亲自测试 可用!
今天很高兴 终于系统的实现了八大排序算法!不说了 直接上代码 !代码都是自己敲的, 亲测可用没有问题! 另:说一下什么是八大排序算法: 插入排序 希尔排序 选择排序 堆排序 冒泡排序 快速排序 归并排 ...
- SYN2101型 NTP网络时间服务器
SYN2101型 NTP网络时间服务器 时钟校准服务器时间 ntp服务器ntp时间校准服务器使用说明视频链接: http://www.syn029.com/h-pd-56-0_310_1_-1. ...
- C语言实现常用数据结构——堆
#include<stdio.h> #include<stdlib.h> #define CAPACITY 20 /*堆有两个性质: * 1.结构性:堆必须是一颗完全二叉树 * ...
- Python连载8-datetime包函数介绍
一.datetime包(上接连载7内容) 1.函数:datetime (1)用法:输入一个日期,来返回一个datetime类 (2)格式:datetime.datetime(年,月,日,hour=, ...
- Netty源码分析--Channel注册(上)(五)
其实在将这一节之前,我们来分析一个东西,方便下面的工作好开展. 打开启动类,最开始的时候创建了一个NioEventLoopGroup 事件循环组,我们来跟一下这个. 这里bossGroup, 我传入了 ...
- 你的http需要“爱情”
目的是为了更白话的认识http,面对业内人,还有一些吃瓜的... 故事背景描述: 男猪脚在情人节这天给他女票发送了一条信息,"I love U",女主角收到后很开心,也回复了一条信 ...
- 【Netty4】深入学习Netty
Netty is an asynchronous event-driven network application framework for rapid development of mainta ...