1. 類和結構
(1)類和結構實際上都是創建對象的模板,每個對象都包含數據,並提供了處理和訪問數據的方法。
(2)類定義了類的每個對象(稱爲實例)可以包含什麼數據和功能。
(3)結構與類的區別是它們在內存中的存儲方式、訪問方式(類是存儲在堆(heap)上的引用類型,而結構是存儲在棧(stack)上的值類型)和它們的一些特徵(如結構不支持繼承。
(4)結構struct,類Class
2. 類
(1)類中的數據和函數稱爲類的成員。成員的可訪問性可以是public、protected、internal protected、private或internal
2.1 數據成員
(1)數據成員是包含類的數據——字段、常量和事件的成員。數據成員可以是靜態數據。類成員總是實例成員,除非用static進行顯式的聲明。
2.2 函數成員
(1)函數成員提供了操作類中數據的某些功能,包括方法、屬性、構造函數和終結器(finalizer)、運算符以及索引器。
2.2.1 方法
(1)方法的聲明
(2)調用方法:代碼:
namespace study3_2_2_1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Pi is " + MathTest.GetPi());
int x = MathTest.GetSquareOf(5);
Console.WriteLine("Square of 5 is " + x);
MathTest math = new MathTest();
math.value = 30;
Console.WriteLine("Value field of math variable contains " + math.value);
Console.WriteLine("Square of 30 is " + math.GetSquare());
}
}
class MathTest
{
public int value;
public int GetSquare()
{
return value * value;
}
public static int GetSquareOf(int x)
{
return x * x;
}
public static double GetPi()
{
return 3.14159;
}
}
}
結果:
(3)給方法傳遞參數:int通過值傳遞給方法,對應方法對該int的值所做的任何改變都沒有改變原int對象的值。但如果把數組或其他引用類型(如類)傳遞給方法,對應的方法就會使用該引用改變這個數組中的值,而新值會反射在原始數組對象上。
代碼:
namespace study3_2_2_5
{
class Program
{
static void SomeFunction(int[] ints, int i)
{
ints[0] = 100;
i = 100;
}
static void Main(string[] args)
{
int i = 0;
int[] ints = { 0,1,2,4,8};
Console.WriteLine("i = " + i);
Console.WriteLine("ints[0] = " + ints[0]);
Console.WriteLine("Calling SomeFunction.");
SomeFunction(ints, i);
Console.WriteLine("i = " + i);
Console.WriteLine("ints[0] = " + ints[0]);
}
}
}
結果:
(4)ref參數:迫使值參數通過引用傳送給方法。
(5)out參數:傳遞給該方法的變量可以不初始化。
(6)命名參數:參數一般需要按定義的順序傳送給方法。命名參數允許按任意順序傳遞。
(7)可選參數:參數也可以是可選的。必須爲可選參數提供默認值。可選參數還必須是方法定義的最後一個參數。
(8)方法的重載:方法的幾個版本有不同的簽名(即:方法名相同,但參數的個數(和/或)類型不同)。限制:兩個方法不能僅在返回類型上有區別; 兩個方法不能僅根據參數是聲明爲ref還是out來區分。
2.2.2 屬性:屬性(property)的概念是:它是一個方法或一對方法,在客戶端代碼看來,它(們)是一個字段。
(1)只讀和只寫屬性:在屬性定義中省略set訪問器,就可以創建只讀屬性。同樣,在屬性定義中省略get訪問器,就可以創建只寫屬性。
(2)屬性的訪問修飾符:屬性可以有公有的get訪問器和私有或受保護的set訪問器。
(3)自動實現的屬性:
(4)內聯:
2.2.3 構造函數:
(1)聲明基本構造函數的語法就是聲明一個與包含的類同名的方法,但該方法沒有返回類型。
(2)構造函數的重載遵循與其他方法相同的規則。
(3)如果提供了帶參數的構造函數,編譯器就不會自動提供默認的構造函數。只有在沒有定義任何構造函數時,編譯器纔會自動提供默認的構造函數
2.2.3.1 靜態構造函數:
(1)C#的一個新特徵是也可以給類編寫無參數的靜態構造函數。這種構造函數只執行一次,而前面的構造函數是實例構造函數,只要創建類的對象,就會執行它。
(2)編寫靜態構造函數的一個原因是,類有一些靜態字段或屬性,需要在第一次使用類之前,從外部源中初始化這些靜態字段和屬性。
(3)注意,無參數的實例構造函數與靜態構造函數可以在同一個類中同時定義。
(4)代碼:
namespace study3_2_2_3
{
public class UserPreferences
{
public static readonly Color BackColor;
static UserPreferences()
{
DateTime now = DateTime.Now;
if (now.DayOfWeek == DayOfWeek.Thursday || now.DayOfWeek == DayOfWeek.Wednesday)
{
BackColor = Color.Green;
}
else
{
BackColor = Color.Red;
}
}
private UserPreferences()
{
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("User-preferences:BackColor is: " +
UserPreferences.BackColor.ToString());
}
}
}
(5)結果:
2.2.3.2 從構造函數中調用其他構造函數
(1)C#有一個特殊的語法,稱爲構造函數初始化器。
(2)這裏this關鍵字僅調用參數最匹配的那個構造函數。注意,構造函數初始化器在構造函數的函數體之前執行。
2.3 只讀字段
(1)readonly關鍵字比const靈活得多,允許把一個字段設置爲常量,但還需要執行一些計算,以確定它的初始值。
(2)其規則是可以在構造函數中給只讀字段賦值,但不能在其他地方賦值。只讀字段還可以是一個實例字段,而不是靜態字段,類的每個實例可以有不同的值。與const字段不同,如果要把只讀字段設置爲靜態,就必須顯式聲明它。
3. 匿名類型
(1)var關鍵字,用於表示隱式類型化的變量。var與new關鍵字一起使用時,可以創建匿名類型。匿名類型只是一個繼承自Object 且沒有名稱的類。該類的定義從初始化器中推斷,類似於隱式類型化的變量。
(2)var captain = new (FirstName = "James", MiddleName = "T", LastName = "Kirk");
4. 結構
(1)有時僅需要一個小的數據結構。此時,類提供的功能多於我們需要的功能,由於性能原因,最好使用結構。
(2)爲結構定義函數與爲類定義函數完全相同
(3)結構是值類型,不是引用類型。它們存儲在棧中或存儲爲內聯。
(4)結構不支持繼承;對於結構構造函數的工作方式有一些區別。尤其是編譯器總是提供一個無參數的默認構造函數,它是不允許替換的;使用結構,可以指定字段如何在內存中的佈局。
4.1 結構是值類型
(1)雖然結構是值類型,但在語法上常常可以把它們當作類來處理。
(2)因爲結構是值類型,所以New運算符與類和其他引用類型的工作方式不同。New運算符並不分配堆中的內存,而是隻調用相應的構造函數,根據傳送給它的參數,初始化所有的字段。對於結構,變量聲明實際上是爲整個結構在棧中分配空間,所以就可以爲它賦值了。
(3)結構遵循其他數據類型都遵循的規則:在使用前所有的元素都必須進行初始化。在結構上調用new運算符,或者給所有的字段分別賦值,結構就完全初始化了。當然,如果結構定義爲類的成員字段,在初始化包含的對象時,該結構會自動初始化爲0。
(4)結構主要用於小的數據結構。但當把結構作爲參數傳遞給方法時,應把它作爲ref參數傳遞,以避免性能損失——此時只傳遞了結構在內存中的地址,這樣傳遞速度就與在類中的傳遞速度工樣快了。但如果這樣做,就必須注意被調用的方法可以改變結構的值。
4.2 結構和繼承
(1)結構不支持繼承。
4.3 結構的構造函數
(1)爲結構定義構造函數的方式與爲類定義構造函數的方式相同,但不允許定義無參數的構造函數。
5. 部分類
(1)partial關鍵字允許把類、結構或接口放在多個文件中。編譯時,只會生成一個類,而類中有各個文件中的方法。
6. 靜態類
(1)如果類只包含靜態的方法和屬性,該類就是靜態的。靜態類在功能上與使用私有靜態構造函數創建的類相同。不能創建靜態類的實例。使用static關鍵字。
7. Object類
7.1 System.Object()方法
- ToString()
- GetHashtable()
- Equals()和ReferenceEquals()
- Finalize()
- GetType()
- MemberwiseClone()
7.2 ToString()
(1)代碼:
namespace study3_7_2
{
class Program
{
static void Main(string[] args)
{
Money cash1 = new Money();
cash1.Amount = 40M;
Console.WriteLine("cash1.ToString() returns:" + cash1.ToString());
Console.ReadLine();
}
}
public class Money
{
private decimal amount;
public decimal Amount
{
get { return amount; }
set { amount = value; }
}
public override string ToString()
{
return "$"+Amount.ToString();
}
}
}
(2)結果:
8. 擴展方法
(1)擴展方法,允許改變一個類,但不需要該類的源代碼。擴展方法是靜態方法。
(2)對於擴展方法,第一個參數是要擴展的類型,它放在this關鍵字的後面。這告訴編譯器,這個方法是Money類型的一部分。
(3)在主程序中,擴展方法看起來像是另一個方法。它沒有顯示第一個參數,也不能對它進行任何處理。如:
public statio class MoneyExtension
{
public static void AddToAmount(this MOney money, decimal amountToAdd)
{
money.Amount += amountToAdd;
}
}
主:cash1.AddToAmount(10M);