var alimama_pid="mm_10096109_566393_892989"; var alimama_titlecolor="0000FF"; var alimama_descolor ="000000"; var alimama_bgcolor="FFFFFF"; var alimama_bordercolor="E6E6E6"; var alimama_linkcolor="008000"; var alimama_bottomcolor="FFFFFF"; var alimama_anglesize="0"; var alimama_bgpic="0"; var alimama_icon="0"; var alimama_sizecode="11"; var alimama_width=760; var alimama_height=90; var alimama_type=2;
C# 3.0 之新特性總結 LazyBee 現在VS2008已經發布,而且很多人也都開始使用C# 3.0了,我在這裡對其新特性做一個總結,以方便自己日後或同仁參考: 1 隱式類型本地變量(var) 這個和以前VB6中的全能類型var使用了同樣的名字,但在C#中,其實var不是一個實際類型,可以說是一個標記,就是讓編譯器去根據初始化的內容來確定需要使用的合適的類型。例如:var i = 5; 就等效於int i=5; 不過,隱式變量有以下幾個限制: 1 隱式本地變量的聲明必須同時包含一個初始化器。 2 初始化器必須是一個表達式,並且不能是對象或集合初始化器,但可以是包括new關鍵字以及對象或集合初始化器的組合表達式。例如:{1,2,3}是一個集合初始化器,如果你將其賦給一個隱式變量將出現編譯錯誤。(var x={1,2,3}; //錯誤),但是你可以這樣這樣var x=new List<int>{1,2,3};是允許的。 3初始化器表達式在編譯時不能為null.(例如:var i=null; //錯誤:不能為null) 4 由於是隱式本地變量,顧名思義,只能用於本地變量(在方法或屬性中使用的變量). 5 如果在隱式類型本地變量的初始化器的表達式中包含其他聲明變量(包括隱式類型的),那麼這些變量必須是相同(或者可以隱式轉換成相同)的編譯時類型。 例如:var arrayD = new[] { 1, "one", 2, "two" };// 錯誤,不允許混合類型 var n = "Java"; var m = 4; var ff = m + n; //正確 注意:foreanch中使用也是允許的,如: int[] numbers = { 1, 3, 5, 7, 9 }; foreach (var n in numbers) Console.WriteLine(n); 2 對象初始化器 對象初始化器用於指定對象的一個或多個可訪問的字段或屬性的值,通過{和}進行封閉起來,多個字段賦值之間通過逗號分割。具體語法元素是: Ø 對象創建表達式: new 類型(類型參數可選)對象或集合初始化器可選 new 類型 對象或集合初始化器 Ø 對象或集合初始化器: 對象初始化器 集合初始化器 Ø 對象初始化器: {對象成員初始化器列表} Ø 對象成員初始化器列表: 對象成員初始化器 對象成員初始化器列表,對象成員初始化器 Ø 對象成員初始化器: 標識符 = 初始化值 Ø 初始化值: 表達式 對象或成員初始化器 注意:對象或成員初始化器是可以嵌套的,並且初始化器是不包含new關鍵字的。初始化器不能用於結構,初始化器中每個成員最多只能初始化一次。示例:
1public class Point 2 { 3 public int X { get; set; } 4 public int Y { get; set; } 5 } 6 public class Rectangle 7 { 8 Point p1 = new Point{ X = 1,Y = 2 }; 9 Point p2 = new Point{X=3,Y=3}; 10 public Point P1 { get { return p1; } set { p1 = value; } } 11 public Point P2 { get { return p2; } set { p2 = value; } } 12} 13Rectangle r2 = new Rectangle() { P1 =new Point { X = 5, Y = 6 }, P2 = { X = 7, Y = 8 } }; 14
namespace LazyBee.UtilitIEs { public static class Extensions { public static int ToInt32(this string s) { return Int32.Parse(s);} public static T[] Slice<T>(this T[] source, int index, int count) { if (index < 0 || count < 0 || source.Length-index < count) throw new ArgumentException(); T[] result = new T[count]; Array.Copy(source, index, result, 0, count); return result; } } }
然後在你要調用擴展方法的地方導入LazyBee.UtilitIEs命名空間,就可以象如下方式調用: string s = "1234"; int i = s.ToInt32(); // Same as Extensions.ToInt32(s) int[] digits = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int[] e = digits.Slice(4, 3); // Same as Extensions.Slice(digits, 4, 3) 注意: 1 實例方法優先於擴展方法的調用,也就是說只有不存在符合要求的實例方法,才會去查找時候存在擴展方法。 2 擴展方法具有一般靜態方法所擁有的一切特性。 3 擴展方法比實例方法具有更多的限制,以及更低的優先級。所以要盡量少用擴展方法,建議只有在不能增加實例方法的情況下使用。 4 其他類型的擴展成員如屬性、事件、操作目前不支持,不過微軟正在考慮當中。 7 Lambda表達式: 6.1 Lambda表達式提供一種更精簡的方式來寫匿名方法,其語法格式為: Ø 表達式: 賦值表達式 非賦值表達式 Ø 非賦值表達式: 條件表達式 Lambda表達式 查詢表達式 Ø Lambda表達式: (Lambda參數列表可選)=>Lambda表達式體 隱式類型Lambda參數=> Lambda表達式體 Ø Lambda參數列表: 顯式類型Lambda參數列表 隱式類型Lambda參數列表 Ø 顯式類型Lambda參數列表: 顯式類型Lambda參數 顯式類型Lambda參數列表,顯式類型Lambda參數 Ø 顯式類型Lambda參數: 參數修飾符可選 類型 標識符 Ø 隱式類型Lambda參數列表 隱式類型Lambda參數 隱式類型Lambda參數列表,隱式類型Lambda參數 Ø 隱式類型Lambda參數: 標識符 Ø &n Lambda表達式體: 表達式 語句塊 示例: x => x + 1; // Implicitly typed, expression body x => { return x + 1; }; // Implicitly typed, statement body (int x) => x + 1; // Explicitly typed, expression body (int x) => { return x + 1; }; // Explicitly typed, statement body () => Console.WriteLine("OK"); //無參數列表 (x,y) => x*y; // Multiple parameters 注意:1 如果是隱式類型,並且只有一個參數時,可以省略括號,如(x) => x + 1,可以簡寫成x => x + 1 2 隱式類型和顯式類型不能混合使用 6.2 當代理類型和Lambda表達式滿足下列條件時,我們說它們是兼容的,也就是可以將Lambda表達式賦值給該代理類型: 1 代理類型和Lambda表達式具有相通數量的參數; 2 如果Lambda表達式是顯式類型參數列表,那麼每一個參數的類型要和對應的代理類型的參數的類型和修飾符相同;如果是隱式類型參數列表,那麼代理類型中不能有ref和out的參數,根據Lambda表達式體推導出的參數類型要和代理類型的參數一致。 3 如果Lambda表達式體是一個語句塊,並且代理類型的返回值是void,那麼語句塊中不能包含有包含返回值的return語句;如果代理類型的返回值不是void,那麼語句塊必須是包含返回值的return語句,而且返回值的類型要和代理類型的返回值一致。 4 如果Lambda表達式體是一個表達式,並且代理類型的返回值是void,那麼表達式必須是能作為語句的表達式(只能是賦值表達式,對對象或函數的調用,new 表達式,變量的++,--操作表達式之一);如果代理類型的返回值不是void,那麼根據表達式推導出的類型必須能和代理類型的返回值類型一致。 示例: public delegate R Func<T,R>(T t); public delegate void F2(); public delegate R F3<T,R>(T t,R r); Func<int, int> a = x => x + 1; F2 b = () => Console.WriteLine("OK"); F3<int, int> c = (x,y) => x*y; 下例將會出現編譯錯誤: public delegate void F3<T,R>(T t,R r); F3<int, int> c = (x,y) => x*y;//Compile error: Only assignment, call, increment, decrement, and new object expressions can be used as a statement 6.3 當Lambda表達式傳遞給一個沒有指定類型參數的泛型方法時,.Net架構將根據表達式來推導出相應的類型參數,例如: public static class Extensions { public static IEnumerable<S> MySelect<T, S>(this IEnumerable<T> source,Func<T, S> selector) { foreach (T element in source) yIEld return selector(element); } } var contacts = new[] { new {Name = "Chris Smith",PhoneNumbers = new[]{ "206-555-0101", "425-882-8080" }}, new {Name = "Bob Harris",PhoneNumbers = new[] { "650-555-0199" }}}; IEnumerable<string> name = contacts.MySelect(j => j.Name); 在這裡MySelect是一個擴展函數,所以contacts.MySelect(j => j.Name)運行時將翻譯成Extensions.MySelect(contacts,j => j.Name),在這裡T就是包含Name和電話號碼的匿名類型,所以S就是string 類型。 6.4 如果存在兩個相同名稱的帶有Lambda表達式為參數的方法,在隱式轉換過程中輸入參數和返回值的類型以最容易轉換為原則進行匹配,如:
class ItemList<T> : List<T> { public int Sum<T>(Func<T, int> selector) { int sum = 0; foreach (T item in this) sum += selector(item); return sum; } public double Sum<T>(Func<T, double> selector) { double sum = 0; foreach (T item in this) sum += selector(item); return sum; } } class Detail { public int UnitCount; public double UnitPrice;
{ // Comment out this method and the program will still compile.
partial void OnSomethingHappened(String s)
{
Console.WriteLine("Something happened: {0}", s);
}
}
}
8 自動屬性 在我們定義類屬性時,特別是在定義值對象屬性時,通常該屬性對應的字段沒有其他用途,在這種情況下我們可以通過一種簡寫的方式來實現: public class Point { public int X { get; set; } public int Y { get; set; } } 這樣編譯器會自動生成private的字段,然後完成get和set的定義。 9 查詢表達式 將在以後補上