C#圖解教程 第六章 深入理解類

深入理解類

類成員


前兩章闡述了9種類成員中的兩種:字段和方法。本章將會介紹除事件(第14章)和運算符外的其他類成員,并討論其特征。

成員修飾符的順序


字段和方法的聲明可以包括許多如public、private這樣的修飾符。本章還會討論許多其他修飾符。多個修飾符一起使用時,它們需要怎么排序呢?

[特性] [修飾符] 核心聲明

  • 修飾符
    • 修飾符,必須放在核心聲明前
    • 多個修飾符順序任意
  • 特性
    • 特性,必須放在修飾符和核心聲明前
    • 多個特性順序任意

例如,public和static都是修飾符,可以用在一起修飾某個聲明。因為它們都是修飾符,所以順序任意。下面兩行代碼是語義等價的:

public static int MaxVal;
static public int MaxVal;

實例類成員


類的每個實例擁有自己的各個類成員的副本,這些成員稱為實例成員。?
改變一個實例字段的值不會影響任何其他實例成員中的值。?

class D
{public int Mem1;
}
class Progarm
{static void Main(){D d1=new D();D d2=new D();d1.Mem1=10;d2.Mem1=28;Console.WriteLine("d1={0},d2={1}",d1.Mem1,d2.Mem2);}
}

靜態字段


除了實例字段,類還可以擁有靜態字段

  • 靜態字段被類的所有實例共享,所有實例訪問同一內存位置。因此,如果該內存位置的值被一個實例改變了,這種改變對所有實例都可見。
  • 可以使用static修飾符將字段聲明為靜態
class D
{int Mem1;        //實例字段static int Mem2; //靜態字段
}

例:靜態字段演示

  • 因為Mem2是靜態的,類D的兩個實例共享單一的Mem2字段。如果Mem2被改變了,這個改變在兩個實例中都能看到
  • 成員Mem1沒有聲明為static,所以每個實例都有自己的副本
class D
{int Mem1;static int Mem2;...
}
static void Main()
{D d1=new D();D d2=new D();...
}

從類的外部訪問靜態成員


靜態成員可以使用點運算符從類的外部訪問。但因為沒有實例,所以必須使用類名。

類名↓
D.Mem2=5;↑成員名
靜態字段示例
  • 一個方法設置兩個數據成員的值
  • 另一個方法顯示兩個數據成員的值
class D
{int Mem1;static int Mem2;public void SetVars(int v1,int v2){Mem1=v1;Mem2=v2;}public void Display(string str){Console.WriteLine("{0}:Mem1={1},Mem2={2}",str,Mem1,Mem2);}
}
class Program
{static void Main(){D d1=new D(),d2=new D();d1.SetVars(2,4);d1.Display("d1");d2.SetVars(15,17);d2.Display("d2");d1.Display("d1");}
}

靜態成員的生存期
  • 之前我們已經看到了,只有在實例創建后才產生實例成員,實例銷毀后實例成員也就不在存在
  • 即使類沒有實例,也存在靜態成員,并可以訪問
class D
{int Mem1;static int Mem2;...
}
static void Main()
{D.Mem2=5;Console.WriteLine("Mem2={0}",D.Mem2);
}

?
字段與類有關,與實例無關


靜態成員即使沒有類的實例也存在。如果靜態字段有初始化語句,那么會在使用該類的任何靜態成員之前初始化該字段,但沒必要在程序執行的開始就初始化。

靜態函數成員


  • 如同靜態字段,靜態函數成員獨立于任何類實例。無需類實例就可以調用靜態方法
  • 靜態函數成員不能訪問實例成員。只能訪問靜態成員

例:靜態函數與靜態字段

class X
{static public int A;static public void PrintValA(){Console.WriteLine("Value of A:{0}",A);}
}
class Program
{static void Main(){X.A=10;X.PrintValA();}
}

其他靜態類成員類型


下表中為可以聲明為static的類成員類型做了√標記


成員常量


成員常量類似本地常量,只是它被聲明在類聲明中而不是方法內。

class MyClass
{const int IntVal=100;//定義值為100的int類型常量
}
const double PI=3.1416; //錯誤:不能在類型聲明之外

與本地常量類似,初始化成員常量的值在編譯時必須是可計算的。

class MyClass
{const int IntVal1=100;const int IntVal2=2*IntVal1;//正確:因為IntVal的值在前一行已設置
}

與本地常量類似,不能在成員常量聲明后給它賦值

class MyClass
{const int IntVal//錯誤:聲明時必須初始化IntVal=100;     //錯誤:不允許賦值
}

與C和C++不同,在C#中沒有全局變量。每個常量都必須聲明在類型內。

常量與靜態量


成員常量比本地常量更有趣,因為它們表現得像靜態值。它們對類的每個實例都是“可見的”,而且即使沒有類的實例也可以用。與真正的靜態量不同,常量沒有自己的存儲位置,而是在編譯時被編譯器替換。常量類似C和C++中的#define。?
正因為常量在內存沒有存儲位置,所以它也不能作為左值(被賦值)。?
static靜態量是有自己的存儲位置的。

例:常量示例

class X
{public const double PI=3.1416;
}
class Program
{static void Main(){Console.WriteLine("pi={0}",X.PI);}
}

?

雖然常量成員表現得像一個靜態量,但不能將常量聲明為static

static const double PI=3.14;//錯誤:不能將常量聲明為static

屬性


屬性代表類的實例或類中的一個數據項成員。使用屬性看起來像寫入或讀取一個字段,它們語法相同。

與字段類似,屬性有如下特征

  • 它是命名的類成員
  • 它有類型
  • 它可以被賦值和讀取

然而和字段不同,屬性是一個函數成員

  • 它不為數據存儲分配內存
  • 它是執行代碼

屬性是指定的一組兩個匹配的、稱為訪問器的方法

  • set訪問器為屬性賦值
  • get訪問器從屬性獲取
屬性聲明和訪問器
  • set訪問器
    • 擁有一個單獨的、隱式的值參,名稱為value,與屬性的類型相同
    • 擁有一個返回類型void
  • get訪問器
    • 沒有參數
    • 擁有一個與屬性類型相同的返回類型

訪問器的其他重點

  • get訪問器的所有執行路徑必須包含一條return語句,返回一個屬性類型的值
  • 訪問器set、get順序任意,除這兩個訪問器外在屬性上不允許有其他方法
屬性示例

例:名為C1的類,包含一個名為MyValue的屬性

  • 屬性本身沒有任何存儲。訪問器決定如何處理發進來的數據,以及什么數據發出去。示例中,屬性使用TheRealValue字段作為存儲
  • set訪問器接受它的輸入參數value,并把值賦給字段TheRealValue
  • get訪問器只是返回字段TheRealValue的值
class C1
{private int TheRealValue;//字段:分配內存public int MyValue       //屬性:不分配內存{set{TheRealValue=value;}get{return TheRealValue;}}
}

使用屬性
  • 要寫入屬性,在賦值語句的左邊使用屬性名
  • 要讀取屬性,把屬性名用在表達式中
  • 屬性根據是寫入還是讀取,隱式調用訪問器。(不能顯示調用訪問器)
int MyValue
{get{...}set{...}
}
...
MyValue=5;
z=MyValue;
屬性和關聯字段

正如下文C1示例中的。一種常見的方式是在類中將字段聲明為private以封裝字段,并聲明一個public屬性來控制從類的外部對該字段的訪問。?
和屬性關聯的字段常被稱為后備字段、后備存儲。

例:使用public的MyValue來控制對private的TheRealValue的訪問

class C1
{private int TheRealValue=10;//字段:分配內存public int MyValue          //屬性:不分配內存{set{TheRealValue=value;}get{return TheRealValue;}}
}
class Program
{static void Main(){C1 c=new C1();Console.WriteLine("MyValue:{0}",c.MyValue);c.MyValue=20;Console.WriteLine("MyValue:{0}",c.MyValue);}
}

屬性和它后備字段的命名有兩種約定。?
約定一:屬性使用Pascal大小寫,字段使用Camel大小寫。雖然這違反了“僅使用大小寫區分不同標識符是壞習慣”。但勝在簡單,有意義。?
約定二:屬性使用Pascal大小寫,字段使用Camel大小寫并在開頭加"_"號。

private int firstField;
public int FirstField
{get{return firstField;}set{firstField=value;}
}
private int _secondField;
public int SecondField
{get{return _secondField;}set{_secondField=value;}
}
執行其他計算

屬性訪問器不僅對后備字段傳進傳出數據。也可以執行任何計算。?
例:通過set屬性訪問器限制Hour的最大值為24

int Hour=12;
int MyValue
{set{Hour=value>24?24:value;}get{return Hour;}
}

上面示例中,演示的條件運算符,將在第8章詳細闡述。?
條件運算符是一種三元運算符,計算問號前的表達式,如果表達式結果為true,則返回問號后第一個表達式,否則,返回冒號后的表達式。

只讀和只寫屬性
  • 只有get訪問器的屬性稱為只讀屬性。只讀屬性是一種安全的,把一項數據從類或類的實例中傳出,而不允許太多訪問方法
  • 只有set訪問器的屬性稱為只寫屬性,只寫屬性是一種安全的,把一項數據從類的外部傳入類,而不允許太多訪問方法
  • 兩個訪問器中至少要定義一個

屬性與公共字段

按照推薦的編碼實踐,屬性比公共字段更好

  • 屬性是函數型成員而不是數據成員,允許你處理輸入和輸出,而公共字段不行
  • 屬性可以只讀或只寫,字段不行
  • 編譯后的變量和編譯后的屬性語義不同
計算只讀屬性示例

例:類RightTriangle(直角三角形)的只讀屬性Hypotenuse(斜邊)

  • 它有兩個公有字段,表示直角三角形的兩個直角邊長度。這些字段可以被寫入、讀取
  • 第三邊由屬性Hypotenuse表示,是只讀屬性,其返回值基于另外兩邊長度
class RightTriangle
{public double A=3;public double B=4;public double Hypotenuse{get{return Math.Sqrt((A*A)+(B*B));}}
}
class Program
{static void Main(){var c=new RightTriangle();Console.WriteLine("Hypotenuse:{0}",c.Hypotenuse);}
}

自動實現屬性

因為屬性經常關聯到后備字段,C#提供了自動實現屬性(automatically implemented property),允許只聲明屬性而不聲明后備字段。編譯器為你創建隱藏的后備字段,并且字段掛接到get和set訪問器上。?
自動屬性的要點如下

  • 不聲明后備字段-編譯器根據屬性類型分配存儲
  • 不能提供訪問器的方法體-它們必須被簡單地聲明為分號。get相當于簡單的內存讀,set相當于簡單的寫
  • 除非通過訪問器,否則不能訪問后備字段。因為不能用其他方法訪問,所以實現只讀和只寫屬性沒有意義,因此使用自動屬性必須同時提供讀寫訪問器。

例:自動屬性

class C1
{public int MyValue          //屬性:分配內存{set;get;}
}
class Program
{static void Main(){C1 c=new C1();Console.WriteLine("MyValue:{0}",c.MyValue);c.MyValue=20;Console.WriteLine("MyValue:{0}",c.MyValue);}
}

除方便以外,自動屬性使你在傾向于使用公有字段的地方很容易用屬性將其替代。

靜態屬性

屬性也可以聲明為static。靜態屬性的訪問器和靜態成員一樣,具有以下特點

  • 不能訪問類的實例成員–它們能被實例成員訪問
  • 不管類是否有實例,它們都存在
  • 當從類的外部訪問時,必需使用類名引用

例:靜態屬性

class Trivial
{public static int MyValue{get;set;}public void PrintValue(){Console.WriteLine("Value from inside:{0}",MyValue);}
}
class Program
{static void Main(){Console.WriteLine("Init Value:{0}",Trival.MyValue);Trival.MyValue=10;Console.WriteLine("New Value:{0}",Trival.MyValue);var tr=new Trivial();tr.PrintValue();}
}

實例構造函數


實例構造函數是一個特殊的方法,它在創建類的每個新實例時執行。

  • 構造函數用于初始化類實例的狀態
  • 如果希望從類的外部創建類的實例,需要將構造函數聲明為public
class MyClass
{         和類名相同↓public MyClass(){     ↑沒有返回類型...}
}
  • 構造函數的名稱與類相同
  • 構造函數不能有返回值

例:使用構造函數初始化TimeOfInstantiation字段為當前時間

class MyClass
{DateTime TimeOfInstantiation;...public MyClass(){TimeOfInstantiation=DateTime.Now;}...
}

在學完靜態屬性后,我們可以仔細看看初始化TimeOfInstantiation那一行。DateTime類(實際上它是一個結構,但由于還沒介紹結構,你可以先把它當成類)是從BCL中引入的,Now是類DateTime的靜態屬性。Now屬性創建一個新的DateTime類實例,將其初始化為系統時鐘中的當前日期和時間,并返回新DateTime實例的引用。

帶參數的構造函數
  • 構造函數可以帶參數。參數語法和其他方法完全相同
  • 構造函數可以被重載

例:有3個構造函數的Class

class Class1
{int Id;string Name;public Class1(){Id=28;Name="Nemo";}public Class1(int val){Id=val;Name="Nemo";}public Class1(String name){Name=name;}public void SoundOff(){Console.WriteLine("Name{0},Id{1}",Name,Id);}
}
class Program
{static void Main(){CLass1 a=new Class1(),b=new Class1(7),c=new Class1("Bill");a.SoundOff();b.SoundOff();c.SoundOff();}
}

默認構造函數

如果在類的聲明中沒有顯式的提供實例構造函數,那么編譯器會提供一個隱式的默認構造函數,它有以下特征。

  • 沒有參數
  • 方法體為空

只要你聲明了構造函數,編譯器就不再提供默認構造函數。

例:顯式聲明了兩個構造函數的Class2

class Class2
{public Class2(int Value){...}public Class2(string Value){...}
}
class Program
{static void Main(){Class2 a=new Class2();//錯誤!沒有無參數的構造函數...}
}
  • 因為已經聲明了構造函數,所以編譯器不提供無參數的默認構造函數
  • 在Main中試圖使用無參數的構造函數創建實例,編譯器產生一條錯誤信息

靜態構造函數


實例構造函數初始化類的每個新實例,static構造函數初始化類級別的項。通常,靜態構造函數初始化類的靜態字段。

  • 初始化類級別的項
    • 在引用任何靜態成員之前
    • 在創建類的任何實例之前
  • 靜態構造函數在以下方面與實例構造函數類似
    • 靜態構造函數的名稱和類名相同
    • 構造函數不能返回值
  • 靜態構造函數在以下方面和實例構造函數不同
    • 靜態構造函數聲明中使用static
    • 類只能有一個靜態構造函數,而且不能帶參數
    • 靜態構造函數不能有訪問修飾符
class Class1
{static Class1{...}
}

關于靜態構造函數還有其他要點

  • 類既可以有靜態構造函數也可以有實例構造函數
  • 如同靜態方法,靜態構造函數不能訪問類的實例成員,因此也不能是一個this訪問器
  • 不能從程序中顯式調用靜態構造函數,系統會自動調用它們,在:
    • 類的任何實例被創建前
    • 類的任何靜態成員被引用前

靜態構造函數示例

class RandomNumberClass
{private static Random RandomKey;static RandomNumberClass(){RandomKey=new Random();}public int GetRandomNumber(){return RandomKey.Next();}
}
class Program
{static void Main(){var a=new RandomNumberClass();var b=new RandomNumberClass();Console.WriteLine("Next Random #:{0}",a.GetRandomNumber());Console.WriteLine("Next Random #:{0}",b.GetRandomNumber());}
}

對象初始化語句


對象初始化語句擴展了創建語法,允許你在創建新的對象實例時,設置字段和屬性的值。


例:

new Point {X=5,Y=6};
  • 創建對象的代碼必須能夠訪問初始化的字段和屬性。如上例中,X和Y必須是public
  • 初始化發生在構造方法執行之后,因為構造方法中設置的值可能會在對象初始化中重置為不同的值
public class Point
{public int X=1;public int Y=2;
}
class Program
{static void Main(){var pt1=new Point();var pt2=new Point(X=5,Y=6);Console.WriteLine("pt1:{0},{1}",pt1.X,pt1.Y);Console.WriteLine("pt2:{0},{1}",pt2.X,pt2.Y);}
}

析構函數


析構函數(destructor)執行在類的實例被銷毀前需要的清理或釋放非托管資源行為。非托管資源通過Win32 API獲得文件句柄,或非托管內存塊。使用.NET資源無法得到它們,因此如果堅持使用.NET類,就無需為類編寫析構函數。?
因此,我們等到第25章再描述析構函數。

readonly修飾符


字段可用readonly修飾。其作用類似于將字段聲明為const,一旦值被設定就不能改變。

  • const字段只能在字段聲明語句中初始化,而readonly字段可以在下列任意位置設置它的值
    • 字段聲明語句,類似const
    • 類的任何構造函數。如果是static字段,初始化必須在靜態構造函數中完成
  • const字段的值必須在編譯時決定,而readonly字段值可以在運行時決定。這種增加的自由性允許你在不同環境或構造函數中設置不同的值
  • 和const不同,const的行為總是靜態的,而readonly字段有以下兩點
    • 它可以是實例字段,也可以是靜態字段
    • 它在內存中有存儲位置

例:Shape類,兩個readonly字段

  • 字段PI在它的聲明中初始化
  • 字段NumberOfSides根據調用的構造函數被設置為3或4
class Shape
{readonly double PI=3.1416;readonly int NumberOfSides;public Shape(double side1,double side2){// 矩形NumberOfSides=4;...}public Shape(double side1,double side2,double side3){// 三角形NumberOfSides=3;...}
}

this關鍵字


this關鍵字在類中使用,表示對當前實例的引用。它只能被用在下列類成員的代碼塊中。

  • 實例構造函數
  • 實例方法
  • 屬性和索引器的實例訪問器

靜態成員不是實例的一部分,所以不能在靜態函數成員中使用this。換句話說,this用于下列目的:

  • 用于區分類的成員和本地變量或參數
  • 作為調用方法的實參

例:MyClass類,在方法內使用this關鍵字區分兩個Var1

class MyClass
{int Var1=10;public int ReturnMaxSum(int Var1){          參數  字段↓    ↓return Var1>this.Var1?Var1:this.Var1;}
}
class Program
{static void Main(){var mc=new MyClass();Console.WriteLine("Max:{0}",mc.ReturnMaxSum(30));Console.WriteLine("Max:{0}",mc.ReturnMaxSum(5));}
}

索引器


假如我們定義一個Employee類,它帶有3個string型字段,如果不用索引器,我們用字段名訪問它們。

class Employee
{public string LastName;public string FirstName;public string CityOfBirth;
}
class Program
{static void Main(){var emp1=new Employee();emp1.LaseName="Doe";emp1.FirstName="Jane";emp1.CityOfBirth="Dallas";}
}

如果能使用索引訪問它們將會很方便,好像該實例是字段的數組一樣。

    static void Main(){var emp1=new Employee();emp1[0]="Doe";emp1[1]="Jane";emp1[2]="Dallas";}

什么是索引器

索引器是一組get和set訪問器,與屬性類似。

索引器和屬性

索引器和屬性在很多方法類似

  • 和屬性一樣,索引器不用分配內存來存儲
  • 索引器通常表示多個數據成員

可以認為索引器是為類的多個數據成員提供get、set屬性。通過索引器,可以在許多可能的數據成員中進行選擇。索引器本身可以是任何類型。

關于索引器的注意事項

  • 和屬性一樣,索引器可以只有一個訪問器,也可以兩個都有
  • 索引器總是實例成員,因此不能聲明為static
  • 和屬性一樣,實現get、set訪問器的代碼不必一定關聯到某字段或屬性。這段代碼可以什么都不做,只要get訪問器返回某個指定類型值即可
聲明索引器
  • 索引器沒有名稱。在名稱的位置,關鍵詞是this
  • 參數列表在方括號中
  • 參數列表中至少聲明一個參數
Return Type this [Type param1,...]
{get{...}set{...}
}

聲明索引器類似于聲明屬性。


索引器的set訪問器

當索引器被用于賦值時,set訪問器被調用,并接受兩項數據

  • 一個隱式參數,名為value,value持有要保存的數據
  • 一個或多個索引參數,表示數據應該保存在哪里

下圖例表明set訪問器有如下語義

  • 它的返回類型為void
  • 它使用的參數列表和索引器聲明中的相同
  • 它有一個名為value的隱式參數,值參類型和索引類型相同

索引器的get訪問器

get訪問器方法體內的代碼必須檢查索引參數,確定它表示哪個字段,并返回字段值。?
get訪問器有如下語義

  • 它的參數列表和索引器聲明中的相同
  • 它返回與索引器相同類型的值

關于索引器的補充

和屬性一樣,不能顯示調用get、set訪問器。取而代之,當索引器用在表達式中取值時,將自動調用get訪問器。索引器被賦值時,自動調用set訪問器。?
在“調用”索引器時,要在方括號中提供參數。

   索引   值↓    ↓
emp[0]="Doe";           //調用set訪問器
string NewName=emp[0];  //調用get訪問器
為Employee示例聲明索引器

下面代碼為示例中的類Employee聲明了一個索引器

  • 索引器需要去寫string類型的值,所以string必須聲明為索引器的類型。它必須聲明為public,以便從類外部訪問
  • 3個字段被強行索引為整數0-2,所以本例中方括號中間名為index的形參必須為int型
  • 在set訪問器方法體內,代碼確定索引指的是哪個字段,并把隱式變量value賦給它。在get訪問器方法體內,代碼確定索引指的哪個字段,并返回該字段的值
class Employee
{public string LastName;public string FirstName;public string CityOfBirth;public string this[int index]{set{switch(index){case 0:LaseName=value;break;case 1:FirstName=value;break;case 2:CityOfBirth=value;break;default:throw new ArgumentOutOfRangeException("index");}}get{switch(index){case 0:return LaseName;case 1:return FirstName;case 2:return CityOfBirth;default:throw new ArgumentOutOfRangeException("index");}}}
}
另一個索引器示例

例:為類Class1的兩個int字段設置索引

class Class1
{int Temp0;int Temp1;public int this[int index]{get{return(index==0?Temp0:Temp1;)}set{if(index==0){Temp0=value;}else{Temp1=value;}}}
}
class Example
{static void Main(){var a=new Class1();Console.WriteLine("Values -- T0:{0},T1:{1}",a[0],a[1]);a[0]=15;a[1]=20;Console.WriteLine("Values--T0:{0},T1:{1}",a[0],a[1]);}
}

索引器重載

類可以有任意多個參數列表不同的索引器。(返回類型不同,不是重載)

例:下面示例有3個索引器

class Myclass
{public string this[int index]{get{...}set{...}}public string this[int index1,int index2]{get{...}set{...}}public int this[float index1]{get{...}set{...}}
}

訪問器的訪問修飾符


本章中,你已看到了兩種帶get、set訪問器的函數成員:屬性和索引器。默認情況下,成員的兩個訪問器的訪問級別和成員自身相同。也就是說,如果一個屬性有public訪問級別,那么它的兩個訪問器也是public的。

不過,你可以為兩個訪問器分配不同訪問級別。例如,下面代碼演示了一個常見且重要的例子–set訪問器聲明為private,get訪問器聲明為public。(get之所以是public,是因為屬性的訪問級別就是public)

注意:在這段代碼中,盡管可以從類的外部讀取該屬性,但卻只能在類的內部設置它。這是非常重要的封裝工具。

class Person
{public string Name{get;private set;}public Person(string name){Name=name;}
}
class Program
{static public void Main(){var p=new Person("Capt,Ernest Evans");Console.WriteLine("Person's name is {0}",p.Name);}
}

訪問器的訪問修飾符有幾個限制。最重要的限制如下。

  • 僅當成員(屬性或索引器)既有get訪問器也有set訪問器時,其訪問器才能有訪問修飾符
  • 雖然兩個訪問器都必須出現,但它們中只能有一個有訪問修飾符
  • 訪問器的訪問修飾符必須比成員的訪問級別有更嚴格的限制性,即訪問器的訪問級別必須比成員的訪問級別低,詳見下圖

例如,如果一個屬性的訪問級別是public,在圖里較低的4個級別中,它的訪問器可以使用任意一個。但如果屬性的訪問級別是protected,則其訪問器唯一能使用的訪問修飾符是private。

分部類和分部類型


類的聲明可以分割成幾個分部類的聲明

  • 每個分部類的聲明都含有一些類成員的聲明
  • 類的分部類聲明可以在同一文件中也可以在不同文件中

每個局部聲明必須標為partial class,而不是class。分部類聲明看起來和普通類聲明相同。

類型修飾符partial不是關鍵字,所以在其他上下文中,可以把它用作標識符。但直接用在關鍵字class、struct或interface前時,它表示分部類型。

例:分部類


Visual Studio為標準的Windows程序模板使用了這個特性。當你從標準模板創建ASP.NET項目、Windows Forms項目或Windows Persentation Foudation(WPF)項目時,模板為每個Web頁面、表單、WPF窗體創建兩個類文件。

  • 一個文件的分部類包含由VS生成的代碼,聲明了頁面上的組件。你不應該修改這個文件中的分部類,因為如果修改頁面組件,VS會重新生成
  • 另一個文件包含的分部類可用于實現頁面或表單組件的外觀和行為
  • 除了分部類,還有另外兩種分部類型
    • 局部結構(第10章)
    • 局部接口(第15章)

分部方法


分部方法是聲明在分部類中不同部分的方法。?
分部方法的兩個部分如下

  • 定義分部方法聲明
    • 給出簽名和返回類型
    • 聲明的實現部分只是一個分號
  • 實現分部方法聲明
    • 給出簽名和返回類型
    • 是以正常形式的語句塊實現

關于分部方法需要了解的重要內容如下

  • 定義聲明和實現聲明的簽名和返回類型必須匹配。簽名和返回類型有如下特征
    • 返回類型必須是void
    • 簽名不能包括訪問修飾符,這使分部方法是隱式私有的
    • 參數列表不能包含out參數
    • 在定義聲明和實現聲明中都必須包含上下文關鍵字partial,直接放在關鍵字void前
  • 可以有定義部分而沒有實現部分。這種情況下,編譯器把方法的聲明以及方法內部任何對方法的調用都移除。不能只有實現部分而沒有定義部分。

下面是一個名為PrintSum的分部方法的示例

  • 因為分部方法是隱式私有的,PrintSum不能從類的外部調用。方法Add是調用PrintSum的公有方法
partial class MyClass
{必須是void↓partial void PrintSum(int x,int y);//定義分部方法public void Add(int x,int y){PrintSum(x,y);}
}
partial class MyClass
{partial void PrintSum(int x,int y)//實現分部方法{Console.WriteLine("Sum i {0}",x+y);}
}
class Program
{static void Main(){var mc=new MyClass();mc.Add(5,6);}
}

?

from:?http://www.cnblogs.com/moonache/p/6097402.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276650.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276650.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276650.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Apache用戶身份驗證

原文鏈接:http://www.yylog.org/?p4830 Apache用戶身份驗證 在apache應用過程中,管理員經常需要對apache下的目錄做一些限制,不希望所有用戶都能訪問該目錄下的文件,只對指定用戶訪問,此時我們就要用到apache用戶身…

攜程elong相繼牽手支付寶轉“危”為“機”

新華網浙江頻道1月16日電 自電子機票全面普及以來,航空公司機票直銷的力度不斷加強正給傳統的機票代理甚至在線旅游平臺帶來了極大的生存壓力。 而面對危機,在進一步豐富自身產品服務之外,大的在線旅行平臺也終于找到對策。繼eLong此前與支付…

c# 獲取word表格中的內容_Java 獲取、刪除Word文本框中的表格

本文介紹如何來獲取Word文本框中包含的表格,以及刪除表格。程序測試環境包括:IDEAJDK 1.8.0Spire.Doc.jar注:jar導入,可通過創建Maven程序項目,并在pom.xml中配置Maven倉庫路徑,并指定Free Spire.Doc for J…

Array.prototype.reduce 的理解與實現

Array.prototype.reduce 是 JavaScript 中比較實用的一個函數,但是很多人都沒有使用過它,因為 reduce 能做的事情其實 forEach 或者 map 函數也能做,而且比 reduce 好理解。但是 reduce 函數還是值得去了解的。 reduce 函數可以對一個數組進行…

PS摳圖方法[photoshop中文教程]

PS摳圖方法 一、魔術棒法——最直觀的方法   適用范圍:圖像和背景色色差明顯,背景色單一,圖像邊界清晰。   方法意圖:通過刪除背景色來獲取圖像。   方法缺陷:對散亂的毛發沒有用。   使用方法&#xff1a…

我的核心技術都是從哪里學到的?如何提高成長的?分享給大家。

1997年,我在讀黑龍江大學讀大二時,我認識了一個內蒙古大學計算機專業畢業的一個高材生,那時我那朋友引導了我很多,他那時候在我們家那邊開一個IT公司,他知道如何靠IT技術賺錢,如何靠程序等賺錢,…

python線性回歸算法簡介_Python實現的簡單線性回歸算法實例分析

本文實例講述了Python實現的簡單線性回歸算法。分享給大家供大家參考,具體如下: 用python實現R的線性模型(lm)中一元線性回歸的簡單方法,使用R的women示例數據,R的運行結果: > summary(fit) Call: lm(formula weig…

Object/Relation Mapping 對象關系映射

對象-關系映射(Object/Relation Mapping,簡稱ORM),是隨著面向對象的軟件開發方法發展而產生的。面向對象的開發方法是當今企業級應用開發環境中的主流開發方法,關系數據庫是企業級應用環境中永久存放數據的主流數據存儲…

FastReport使用方法(C/S版)

前言 這兩天群里一直有群友問一些關于FastReport的問題,結合他們的問題,在這里做一個整理,有不明白的可以加 FastReport 交流群 群 號:554714044 工具 VS2017 FastReport 開始 1.新建項目,添加三個按鈕。預覽、設計、…

如何設置Linux時區為東八區

當我們購買美國VPS或服務器的時候,默認情況下是美國時間。對于我們定時執行某些任務會帶來麻煩,所以需要設置時區為東八區。登錄SSH后,執行tzselect命令。我們這里選擇亞洲5.這里選擇china 9。一般選東八區(北京,廣東&…

python刪除兩個excel表中的相同元素_python篩選出兩個文件中重復行的方法

查找A文件中&#xff0c;與B文件中內容不重復的內容#!usr/bin/python import sys import os字符串查找函數&#xff0c;使用二分查找法在列表中進行查詢def binarySearch(value, lines): right len(lines) - 1 left 0 a value.strip() while left < right: middle int((…

求解:nhibernate2.0操作oralce提交事務時報錯

代碼如下: Configuration config new Configuration(); config.AddAssembly("TestCleanSnow"); ISessionFactory factory config.BuildSessionFactory(); ISession session f…

python畫楓葉_python-文件的操作

一、異常 程序在運行的過程中&#xff0c;不可避免出現一些錯誤&#xff0c;這些錯誤成為異常 異常以后的代碼都不會被執行 try 語句 代碼塊&#xff08;可能出現錯誤的語句&#xff09; except 異常類型 as 異常名: 代碼塊(出錯以后執行的語句&#xff09; except 異常類型 as…

記2018年技術人一次短暫的創業

背景 2018年8月底&#xff0c;我全職加入了一家創業公司&#xff0c;具體做什么我暫時先不說吧&#xff0c;我是產品和技術負責人&#xff0c;自己出資了50w&#xff0c;大股東&#xff08;下面簡稱T)也就是ceo是早期阿里出身的中供銷售&#xff0c;從2017年11月開始成立此公司…

如何在Apache環境下配置Rewrite規則

原文鏈接&#xff1a;http://faq.comsenz.com/viewnews-12 URL 靜態化是一個利于搜索引擎的設置&#xff0c;通過 URL 靜態化&#xff0c;達到原來是動態的 PHP 頁面轉換為靜態化的 HTML 頁面&#xff0c;當然&#xff0c;這里的靜態化是一種假靜態&#xff0c;目的只是提高搜…

情 人 節 快 樂

我不善于用詞匯修飾我的句子&#xff0c; 我不善于用表情表達我的心情&#xff0c; 我不善于解讀你那黯然的情緒&#xff0c; 我不善于去響應你小小的呼應&#xff0c; 雖然&#xff0c;你了解我&#xff0c; 你寬容于我&#xff0c; 你聽我訴說&#xff0c; 你陪伴著我…

Windows 10系統安裝JDK1.8與配置環境

第一步&#xff1a;下載JDK1.8 地址:https://www.oracle.com/index.html 第二步&#xff1a; 安裝分兩次&#xff0c;第一次是安裝 jdk &#xff0c;第二次是安裝 jre 。安裝jdk默認的安裝地址為C盤&#xff0c;安裝目錄 \java 之前的目錄修改成你想放的目錄&#xff1b;安裝jr…

python3函數調用時間_Python3 time clock()方法

Python3 time clock()方法 描述 Python 3.8 已移除 clock() 方法 可以使用 time.perf_counter() 或 time.process_time() 方法替代。 Python time clock() 函數以浮點數計算的秒數返回當前的CPU時間。用來衡量不同程序的耗時&#xff0c;比time.time()更有用。 這個需要注意&am…

給apache安裝mod_rewrite模塊

給apache安裝mod_rewrite模塊 原文鏈接&#xff1a;http://opkeep.com/system/linux/apache_mod_rewrite.html 只是用來做參考,相關情況可跟據自己的需求進行修改 如果你的服務器apache還沒有安裝&#xff0c;那很簡單&#xff0c;在編譯apache時將mod_rewrite模塊編譯進去就可…

Oracle9i 問題匯總--不斷更新中

1.創建數據表時&#xff0c;用戶表空間不足&#xff0c;解決方法 ALTER USER USERNAME QUOTA UNLIMITED ON USERS 2.避免在On條件上使用字符串串連 或者 函數。 如&#xff1a;ON 0||S.LIST_NOMS.EXTEND_FIELD 以上SQL語句會造成查詢嚴重變慢&#xff0c;如果非要使用請使用&…