C# 3.0 于 2008 年初随 VS2008 一起正式发布。
C# 的进化
C# 1.0——托管代码
C# 2.0——泛型,匿名方法
C# 3.0——LINQ,Lambda
C# 3.0 概述
C# 3.0 的新特性包括
自动属性、推断类型、匿名类、扩展方法、对象初始化器、集合初始化器、Lambda 表达式、LINQ
——自动属性
普通类:
class Person
{
private string firstName;
private string lastName;
private int age;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
public int Age
{
get { return age; }
set { age = value; }
}
}
使用了自动属性的类:
class PersonNew
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
演示示例:自动属性
——自动属性本质
使用了自动属性的类,编译器为我们自动生成了这些私有变量
在反汇编后,两者的代码几乎完全一样。
自动属性小结:
自动属性的典型适用场合:
在属性代码中只包含基本的赋值取值功能
简单的实体类
使用自动属性时,需要注意以下几点:
自动属性不能实现只读或者只写属性
因为没有声明私有变量,你在使用自动属性时只能直接使用属性名进行引用
——对象初始化器
传统赋值方式
// ….
Person lincoln = new Person();
lincoln.FirstName = "Lincoln";
lincoln.LastName = "Burrows";
lincoln.Age = 30;
lincoln.SayHi();
// ….
使用对象初始化器赋值
// ….
Person scofield = new Person {
FirstName = "Michael",
LastName = "Scofield",
Age = 20 };
scofield.SayHi();
// ….
演示示例:对象初始化器
——可嵌套的对象初始化器
//可嵌套的对象初始化器
Person tbag = new Person
{
FirstName = "Theodore ",
LastName = "Bagwell",
Age = 32,
Address = new Address
{
Street = "Prison SONA",
Country = "Panama"
}
};
对象初始化器不仅可以包含简单的赋值代码,还可以包含其他的对象初始化器,即嵌套的对象初始化器
——对象初始化器小结
请指出以下代码中的错误:
Person scofield = new Person
(
FirstName = "Michael";
LastName = "Scofield";
Age = 22;
Address = new Address
(
Street = "Prison SONA";
Country = "Panama";
)
);
对象初始化器中
() 应该改为 {}
; 应该改为 ,
Person scofield = new Person
{
FirstName = "Michael",
LastName = "Scofield",
Age = 22,
Address = new Address
{
Street = "Prison SONA",
Country = "Panama",
}
};
——集合初始化器
集合初始化器使我们可以象初始化数组那样初始化集合
传统赋值方式
List<string> foxRiver8 =
new List<string>();
foxRiver8.Add("Michael");
foxRiver8.Add("Lincoln");
foxRiver8.Add("Sucre");
foxRiver8.Add("Abruzzi");
foxRiver8.Add("T-Bag");
foxRiver8.Add("C-Note");
foxRiver8.Add("Tweener");
foxRiver8.Add("Charles");
使用集合初始化器赋值
List<string> foxRiver8 =
new List<string>{
"Michael",
"Lincoln",
"Sucre",
"Abruzzi",
"T-Bag",
"C-Note",
"Tweener",
"Charles"
};
演示示例:集合初始化器
问题
小艾同学从网上下载了一个图形类库(只有DLL,没有源代码),感觉非常好用。但是,其中的 Rectangle 类只有一个计算面积的方法。现在小艾想为它添加一个计算周长的方法,大家帮忙想想看,有什么好办法呢?
扩展方法
——简单的扩展方法
先看一个简单的例子
string greeting = "welcome to beijing";
greeting.SayHi();
字符串类型什么时候多了一个 SayHi() 方法?演示示例:简单的扩展方法
代码分析:
定义扩展方法
//using …..
namespace HelloOrcas
{
static class JBUtility//static:扩展方法必须在静态类中定义
{
//扩展方法是一种特殊的静态方法 static;
//第一个参数前加关键字 this;
//这里的 string 表示将要为所有的 string 类型添加扩展方法
public static void SayHi(this string s)
{
string message = string.Format(
"Hi, 我是一个字符串,我的值是: /"{0}/"。", s);
MessageBox.Show(message, "JBUtility",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Information);
}
}
}
注意回顾 静态方法 和 静态类 概念,可以通过提问总结 this 出现的场合 例如 索引器
——定义扩展方法的语法
语法:不带参数的扩展方法:
static 方法名 (this 目标类型 参数名)
语法:带参数的扩展方法:
static 方法名 (this 目标类型 参数名,参数类型1,参数名1,… …. )
——扩展方法的使用:
使用扩展方法时,请注意:
在一个静态类中定义需要的扩展方法
如果上面定义的扩展方法位于不同的命名空间,使用时记住用 using 语句引用过来
当类本身的方法与扩展方法同名时,优先类本身的方法
——带参数的扩展方法示例:
定义带参数的扩展方法
public static void SayHi(this string s, string caption)
{
string message = string.Format(
"Hi, 我是一个字符串,我的值是: /"{0}/"。", s);
MessageBox.Show(message, caption,
MessageBoxButtons.OKCancel,
MessageBoxIcon.Information);
}
调用带参数的扩展方法
string greeting = "welcome to beijing";
greeting.SayHi("Beijing 2008");
演示示例:带参数的扩展方法
现场编程:
请编写 string 类的扩展方法将字符串转换为 Pascal
大小写格式,要求运行如下代码:
string greeting = "welcome to beijing";
Console.WriteLine(greeting.ToPascal());
输出 WelcomeToBeijing
//参考答案
public static string ToPascal(this string s)
{
string[] words = s.Split(new char[] { ' ' });
string result = string.Empty;
foreach (string word in words)
{
result += word.Substring(0, 1).ToUpper() +
word.Substring(1).ToLower();
}
return result;
}
——扩展方法小结
使用扩展方法时,需要注意以下几点:
扩展方法允许我们对已存在类型的行为进行扩展
扩展方法是一种特殊的静态方法
扩展方法必须在静态类中定义
扩展方法的优先级低于同名的类方法
扩展方法只在特定的命名空间内有效
除非必须不要滥用扩展方法
(使用扩展方法要适度。
过度地使用扩展方法可能造成类的结构变得复杂,行为不可预知
原则上,如果可以写到类本身代码中的方法就不要做成扩展方法)
——var关键字
var是C# 3.0 引入的一个新关键字,它可以根据初始值自动推断局部变量类型。
使用 var 语法:
var i = 2008;
var s = "ACCP";
var d = 5.0;
var numbers = new int[] {1, 2, 3};
var students = new Dictionary<int, Person>();
传统方式:
int i = 2008;
string s = "ACCP";
double d = 5.0;
int[] numbers = new int[] {1, 2, 3};
Dictionary<int, Person > students =
new Dictionary<int, Person >();
两者效果完全一样。
(事实上伴随 var 关键字引入的是一种叫做 “Implicitly Typed Local Variables” 的机制
即 “暗示类型局部变量” 注意 在这里 它清晰地表明 var 修饰的是一个局部变量
所以虽然我们后面有时称呼它为“推断类型” 但实际上它不是一种“类型” 而是“可以推断类型的局部变量”)
——var 与 object 的区别
使用 var:
var name = "Beijing";
name = 2008;
编译错误!
Cannot implicitly convert type 'int' to 'string'
使用 object:
object name = "Beijing";
name = 2008;
可以通过编译'
演示示例:var与object的区别
——匿名类
var p=new{
Name="Tin Tin",
Age=20,
Gender="male"};
Console.WriteLine(p.Name);//虽然是匿名类型,但是因为还是强类型,所以仍能很好地支持智能感应
演示示例:匿名类
——匿名类的本质
编译器自动生成的匿名类名称
——var小结
请判断以下代码的对错
var x;
错误, 必须初始化
var y = {1, 2, 3};
错误, 应改为 var x = new int[] { 1, 2, 3 };
Int i;
var v = i++;
错误, 变量 i 必须先初始化
var z = null;
错误, 初始化值不允许为null
——var小结
使用关键字 var 时,需要注意以下几点:
定义变量时,必须同时完成初始化工作
不允许用 var 定义一个以 null 值初始化的局部变量
var 本身不是一个新类型,本质上,它只是用来修饰一个可以推断出类型的局部变量
——总结
请说出三条以上 C# 3.0 的新特性。
使用 var 和 object 声明变量时有什么区别?
引入扩展方法有什么好处?