C# 类和编程案例
一.
??? “類”是一種構造,通過使用該構造,您可以將其他類型的變量、方法和事件組合在一起,從而創建自己的自定義類型。如果類沒有聲明為靜態類,客戶端代碼就可以創建賦給變量的“對象”或“實例”,從而使用該類。在對變量的所有引用都超出范圍之前,該變
量始終保持在內存中。所有引用都超出范圍時,CLR 將標記該變量以供垃圾回收。如果類聲明為靜態類,則內存中只存在一個副本,并且客戶端代碼只能通過該類自身而不是“實例變量”訪問該類。
??? 與結構不同,類支持“繼承”,而繼承是面向對象編程的基礎特性。
??? 類使用 class 關鍵字進行聲明。
??? class 關鍵字前面是訪問級別。如果使用 public,任何人都可以基于該類創建對象。
??? 對象是基于類的具體實體,有時稱為類的實例。通過使用 new 關鍵字(后跟對象將基于的類的名稱)可以創建對象。
??? 由于基于類的對象是按引用來引用的,因此類稱為引用類型。
??? this關鍵字提供對當前實例的訪問。
二.
類繼承
繼承是通過使用“派生”來實現的,而派生意味著類是使用“基類”聲明的,它的數據和行為從基類繼承。通過在派生的類名后面追加冒號和基類名稱,可以指定基類,例如,
public class Manager : Employee
{
??? // Employee fields, properties, methods and events are inherited
??? // New Manager fields, properties, methods and events go here...
}
當類聲明基類時,它繼承基類除構造函數以外的所有成員。
與 C++ 不同,C# 中的類只能直接從一個基類繼承。但是,因為基類自身也可能繼承自另一個類,所以類可以間接繼承多個基類。而且,一個類可以直接實現一個以上的接口。
類可以聲明為抽象類。抽象類包含具有簽名定義但沒有實現的抽象方法。抽象類不能進行實例化。只能通過實現抽象方法的派生類使用抽象類。相比之下,密封類不允許其他類從其派生。
類定義可在不同的源文件之間進行拆分,這叫分部類。
三.
一個類對象中,主要包括字段、屬性和方法。不過除此之外,在類類型中還可以定義嵌套類,也可以定義一個常量。
常量:
const PI = 3.1415926;
square = PI * radius;
類的字段其實也是變量。字段仍然可以利用public,internal,protected,private來修飾它。不過,建議如非特殊情況,不要將字段修飾為public。因為,根據”對象封裝”的原則,應盡量避免將一個類型的字段以公有方式提供給外部。畢竟,對于字段而言,對象對
它的控制非常弱,一旦公開在外,則調用者可以比較容易的對其進行操作,尤其是寫操作,從而可能會導致錯誤。例如,如果為User類增加一個age(年齡)字段,假如將其定義為public字段,
public int Age;
?
那么調用者可能會將Age的值設為負數:
user.Age = -5;
如果字段不能設置為public,那么調用者又如何訪問它們呢?使用C#類中的property(屬性)。
“屬性”,它利用一種被稱為“get/set訪問器”分別控制對字段的讀寫操作,并暴露一個屬性值,如Age屬性:
private int m_age;
public int Age
{
?get {return m_age;}
?set
?{
? if (value < 0)
? {
?? throw new ArgumentOutOfRangeException("Age must be greater than or equal to 0");
? }
? m_age = value;
?}
}
?
首先,定義一個私有字段m_age,然后再定義一個公共屬性Age。在該屬性中,get返回私有字段的值m_age,而在set中,首先會判斷value的值,如果小于0,那么這個值是非法的,就將拋出一個異常,停止往下執行,并告訴你對Age值的設置錯誤了。當然,也可以為value
值設置更嚴格的要求,例如不允許value大于150。
?
value是什么?它是C#中提供的關鍵字,代表的是賦給該屬性的真正的值,例如:
user.Age = 30;
此時是對Age屬性賦值,.Net會執行set訪問器,而value值就是30。然后判斷30是否小于0。符合條件,不會拋出異常,繼續執行,將value值30賦給字段m_age。
為什么要賦給m_age呢?看看get訪問器,它其實就是一個讀操作,返回的值是什么?就是字段m_age,如下所示:
user.Age = 30;???? //set操作,將字段m_age設置為30;
Console.WriteLine(“User’s Age is {0}.”, user.Age);?? //get操作,將m_age的值取出;
?
此時就會在控制臺下顯示:
User’s Age is 30.
?
此外,對于一些特殊的要求,我們在將字段封裝為屬性時,可以只設置它的get訪問器或者set訪問器,這樣這個屬性就是只讀屬性,或者只寫屬性了。這樣更有利于對象的封裝。
畢竟對于公共字段而言,我們最能可以控制它為只讀(設置為readonly),卻無法設置為只寫。
?
從上可以看到,實際上屬性就是對字段進行一次封裝。
在C# 2.0中,除了可以對整個屬性設置public等訪問修飾符外,對內部的get/set訪問器同樣可以設置訪問修飾符,當然它要受到一定的限制。
訪問器和屬性的訪問修飾符沖突問題。
1、如果整個屬性被設置為public,則其訪問器沒有限制;
2、如果整個屬性被設置為protected internal,則訪問器的訪問修飾僅能設置為internal,protected或者private中的一種;
3、如果整個屬性被設置為internal或者protected,那么訪問器的訪問修飾只能是private。
四
1 使用this進行串聯構造函數調用
使用一項名為構造函數鏈的技術來設計類。當類定義個了多個構造函數時,這個設計模式就會很有用。
由于構造函數通常會檢驗傳入的參數來強制各種業務規則,所以在類的構造函數集合中經常會找到冗余的驗證邏輯。
串聯構造函數方案:讓一個接受最多參數個數的構造函數做“主構造函數”,并實現必須的驗證邏輯。其余的構造函數使用this關鍵字把參數轉給主構造函數,并提供其他必需的參數。這樣,我們只關心主構造函數的邏輯,而其他構造函數體基本是空的了。
使用this關鍵字串聯構造函數方式可以簡化編程任務,類定義更加容易維護、更更加簡明。但它不是強制使用的。
?
串聯構造函數的執行順序:
1、調用構造函數把調用者提供的參數值轉發給主構造函數,并提供其他必須的初始化參數值。
2、執行主構造函數。
3、執行調用構造函數體的邏輯。
2 自定義索引器
class CarCollection:IEnumerable{
?? private ArrayList arCar=new ArrayList();
?? public Car this[int index]
?? {
????? get{ return (Car)arCar[index];}
????? set{arCar.Insert(index,value);}
?? }
?? //...
}
3 static關鍵字
??? C#類(或者結構)可以使用static關鍵字來定義許多靜態成員。這些靜態成員只能從類級別而不能從對象級別上調用(調用靜態成員時不需要創建實例對象)。
?
例如:
//錯誤,WriteLine是靜態成員,是類級別的方法。
Console c=new Console();
c.WriteLine("Bruce Wong");
//正確!WriteLine是類級別的方法
Console.WriteLine("Bruce Wong");
靜態成員只能操作靜態數據或調用類的靜態成員。而非靜態成員可以操作實例數據與靜態數據(成員),因為靜態成員對類的所有實例都是可用的。
CLR把靜態數據分配到內存只進行一次,改變靜態數據將影響此類的所有實例。
?
定義靜態構造函數
??? 構造函數用于在創建類對象時設置類對象的數據值。如果使用實例級別的構造函數給靜態數據賦值,你會發現每次新建類對象時靜態數據的只都會被重置。所以我們要初始化靜態數據最好使用靜態構造函數。
?
??? 靜態構造函數是特殊的構造函數,它非常適用于初始化在編譯時未知的靜態數據的值:
??? 一個類(結構)只能定義一個靜態構造函數。
??? 靜態構造函數不允許訪問修飾符并且不能接受任何參數。
??? 無論創建多少個類實例,靜態函數知執行一次。
??? CLR創建類實例或首次調用類靜態成員前,CLR會調用靜態構造函數。
??? 靜態構造函數先于實例級別的其他構造函數執行。
?
??? 靜態類:一個類被定義為靜態的(使用static關鍵字修飾),就不能使用new關鍵字來創建類實例,靜態類只能包含用static標記的靜態類成員或
?
五 案例
1
碼碼:
using System;
public class Person
{
??? // 字段
??? public string name;
??? // 無參構造函數
??? public Person()
??? {
??????? name = "不知道";
??? }
??? // 帶一個參數構造函數
??? public Person(string nm)
??? {
??????? name = nm;
??? }
??? // 方法
??? public void SetName(string newName)
??? {
??????? name = newName;
??? }
}
class TestPerson
{
??? static void Main()
??? {
??????? // 調用無參構造函數
??????? Person person1 = new Person();
??????? Console.WriteLine(person1.name);
??????? person1.SetName("張三");
??????? Console.WriteLine(person1.name);
??????? // 調用帶一個參數構造函數
??????? Person person2 = new Person("李四");
??????? Console.WriteLine(person2.name);
??????? // 等待拿下鍵再關閉控制臺窗口
??????? Console.WriteLine("按任意鍵繼續......");
??????? Console.ReadKey();
??? }
}
// Output:
// unknown
// John Smith
// Sarah Jones
圖圖:
?
2
碼碼:
/*
?* Created by SharpDevelop.
?* User: Administrator
?* Date: 2015/3/31
?* Time: 13:04
?*
?* To change this template use Tools | Options | Coding | Edit Standard Headers.
?*/
using System;
namespace leidemo2
{
?public class Car{
?//Car的字段(狀態)
??? ?private int _speed;
??? ?private string _name;
?//Car操作字段的屬性
??? ?public int Speed??? {
??????? set {this._speed=value;}
??????? get{return this._speed;}
??}
?public string Name
??? {
??????? set { this._name=value;}
??????? get{return this._name;}
?}
??? ?//顯式定義默認構造函數
??? ?public Car(){}
?? ? //自定義構造函數
??? ?public Car(string name,int speed)
??? {
??????? this._name=name;
??????? this._speed=speed;
?}
?//Car的功能(方法)
?public void ShowState()
?{
??Console.WriteLine("車 {0} 的速度是 {1} MPH", this._name,this. _speed);
?}
?}
?
?class Program
?{
??public static void Main(string[] args)
??{
???//創建Car對象。
???Car car; //聲明了指向尚未創建的Car對象的引用。
???car=new Car("寶馬",150);//通過new把有效的引用賦給對象,這引用才會指向內存有效的對象。
???car.ShowState();
???
???Console.Write("按任意鍵繼續 . . . ");
???Console.ReadKey(true);
??}
?}
}
?
圖圖:
?
?
總結
- 上一篇: 开源框架完美组合之Spring.NET
- 下一篇: C#接口和编程实例