C# 3.0 新文法
C# 3.0 概述
C# 3.0 於 2008 年初隨 VS2008 一起正式發布。
C# 的進化
C# 1.0——Managed 程式碼
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 聲明變數時有什麼區別?
引入擴充方法有什麼好處?