類:類就是擁有相等功能和相同的屬性的對象的集合。
類是C#類型中最基礎(chǔ)的類型硫麻。類是一個數(shù)據(jù)結(jié)構(gòu)爸邢,將狀態(tài)(字段)和行為(方法和其他函數(shù)成員)組合在一個單元中。類提供了用于動態(tài)創(chuàng)建類實例的定義拿愧,也就是對象(object)杠河。類支持繼承(inheritance)和多態(tài)(polymorphism),即派生類能夠擴展和特殊化基類的機制浇辜。
如將哺乳動物劃分為一類券敌,然后人就可以作為哺乳動物的派生類,對哺乳動物的特點繼承柳洋,對于人區(qū)分與其他哺乳動物的內(nèi)容進行重寫待诅,實現(xiàn)多態(tài)。
定義類
定義類的語法為使用關(guān)鍵字 class
語法為
訪問修飾符 class 類名
{
類的成員
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
class A
{
}
static void Main(string[] args)
{
}
}
}
這里的 class A 就是一個最簡單的類
然后就可以在里面添加內(nèi)容熊镣,對類A完善卑雁。
類的成員
類中包含大量成員,主要分為數(shù)據(jù)成員和函數(shù)成員绪囱。
類別 | 說明 | |
---|---|---|
數(shù)據(jù)成員 | 常量 | 與該類相關(guān)聯(lián)的常數(shù)值 |
字段 | 該類的變量 | |
函數(shù)成員 | 方法 | 實現(xiàn)由該類執(zhí)行的計算和操作 |
屬性 | 定義類中的值并對他們進行讀寫{get;set;} | |
事件 | 說明發(fā)生了說明事 | |
索引器 | 允許像使用數(shù)組那樣為類添加路徑列表 | |
運算符 | 定義表達式運算符测蹲,通過他們對該類的實例進行運算 | |
實例構(gòu)造函數(shù) | 規(guī)定在初始化該類的時候需要做什么 | |
靜態(tài)構(gòu)造函數(shù) | 規(guī)定在初始化該類自身時需要做什么 | |
私有構(gòu)造函數(shù) | 保證類不被實例化 | |
構(gòu)析函數(shù) | 規(guī)定永久的放棄該類的一個實例之前需要做什么 | |
類型 | 該類的局部類型 |
數(shù)據(jù)成員
數(shù)據(jù)成員
常量使用 const 關(guān)鍵字聲明。在聲明后變?yōu)槌?shù)值毕箍,且不能改變弛房。
而字段作為與類相關(guān)的變量不需要關(guān)鍵字。
語法為 const 數(shù)據(jù)類型 常量名 ** =** 值;
在創(chuàng)建常量時必須對常量賦值而柑,而字段不需要文捶,但也可以荷逞。
語法為 數(shù)據(jù)類型 變量名;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class A
{
const int x = 10;//定義整形常量x為10
string s = "Hello World!";//定義字段可以賦值
bool p;//也可以不賦值
}
static void Main(string[] args)
{
}
}
}
函數(shù)成員
方法
在類中,方法分為實例方法和靜態(tài)方法粹排。
靜態(tài)方法使用 static 關(guān)鍵字修飾种远。
方法的語法規(guī)則為:
修飾符 返回的類型 方法名 (參數(shù))
{
方法體
}
修飾符表示可訪問的權(quán)限。
返回的類型表示在方法體中 return 返回的數(shù)據(jù)類型顽耳,無返回值用 void坠敷。
方法名自定義,但希望遵守所有首字母大寫的原則射富。
參數(shù)可選膝迎,可以沒有參數(shù),直接使用空括號胰耗;參數(shù)數(shù)量可變限次,可以有多個參數(shù)。
方法體自定義柴灯,為方法要實現(xiàn)的目的撰寫代碼卖漫。可以有多行赠群。在非 ** void**返回類型的方法中要有 return 羊始,且只有一個 return。
方法示例:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class A
{
public static int F1()//無參數(shù)靜態(tài)方法
{
return 777;
}
public static int F2(int x)//有參數(shù)靜態(tài)方法
{
return x;
}
public void F3()
{
WriteLine("000");//無參數(shù)無返回值實例方法
}
public string F4(string x)//有參數(shù)有返回值實例方法
{
return x;
}
public bool F5()//函數(shù)內(nèi)可以有多行
{
WriteLine("為真");
return true;
}
}
static void Main(string[] args)
{
}
}
}
參數(shù)
方法可以有0個查描,1個或多個參數(shù)突委。
對于0個參數(shù)的方法,直接使用空括號叹誉。
對于有固定的數(shù)量的參數(shù)的方法鸯两,依次在括號內(nèi)寫入?yún)?shù)。
對于參數(shù)數(shù)量不固定的方法长豁,需要使用 params 關(guān)鍵字表明要傳入多個參數(shù)钧唐,該關(guān)鍵字只能放在最后一個參數(shù)后面,且只能有一個可變參數(shù)匠襟。
參數(shù)可以在定義時傳入默認值钝侠,在使用的時候如果不傳入?yún)?shù)可以直接使用默認值。但是在設(shè)置有默認值參數(shù)時必須將設(shè)有默認值的參數(shù)放在末尾(params除外酸舍,參數(shù)不固定必須放在末尾)帅韧。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class A
{
public int F1()//無參數(shù)方法
{
return 777;
}
public int F2(int x)//一個參數(shù)方法
{
return x;
}
public int F3(int x1,int x2 = 100,params int[] ls1)//固定數(shù)量參數(shù)方法,且含有默認值
//這里傳入一個可變長度參數(shù)數(shù)組ls1啃勉,使用關(guān)鍵字params忽舟,可變長度參數(shù)只能一個且放在末尾
{
return x1 + x2;
}
public int F4(int x1,bool x2,string x3,double x4)//傳入?yún)?shù)類型不必統(tǒng)一
{
return x1;
}
public int F5(int x1,int x2)
{
return x1 / x2;//通過改變傳入?yún)?shù)順序改變結(jié)果
}
}
static void Main(string[] args)
{
var s = new A();
int a1 = s.F1();
int a2 = s.F2(777);
int a3 = s.F3(9, 10, 1, 2, 3, 4);//如果不傳入第二個參數(shù)10將使用默認值100
int a4 = s.F4(1, true, "asd", 3.14);//盡管只返回其中一個參數(shù),但要傳入所有參數(shù)
int a5 = s.F5(x2:10, x1:100);//使用冒號指定傳入?yún)?shù)名稱從而改變傳入?yún)?shù)順序
//需要對所有參數(shù)表示名稱
WriteLine(a1);
WriteLine("{0}\n{1}\n{2}\n{3}",a2,a3,a4,a5);
ReadKey();
}
}
}
傳參
在傳入?yún)?shù)的時候需要對所有參數(shù)傳入,有默認值除外叮阅。
傳入?yún)?shù)時有默認值時不傳入?yún)?shù)使用默認值刁品。
如果要改變傳入?yún)?shù)順序需要對參數(shù)使用 : 指定名稱。
且指定名稱時所有傳入?yún)?shù)都要指定名稱浩姥。
注意在命名傳參時如果遇到不定長參數(shù)只能傳入這個不定長參數(shù)的其中一個值挑随。
對于內(nèi)容體為一行的方法存在簡略寫法。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class A
{
public int F1()//完整寫法
{
return 777;
}
public int F2() => 777;//簡略寫法
}
static void Main(string[] args)
{
ReadKey();
}
}
}
這里的方法F1和F2的結(jié)果是相同的勒叠,使用 => 省略花括號兜挨,以及 return。
但是注意這里后面需要寫分號眯分。
方法的調(diào)用
方法調(diào)用區(qū)分為兩種類型拌汇。
一種為實例方法,一種為靜態(tài)方法弊决。
對于實例方法在調(diào)用其中的函數(shù)時需要對類進行創(chuàng)建實例對象担猛。實例化可以使用 new關(guān)鍵字。
使用 var 定義一個變量丢氢,使其賦值為類的對象。
語法通常為 var 變量名 = new 類名()先改;
然后對通過類的實例對象的變量名調(diào)用方法疚察。
語法為 變量名.方法名(參數(shù));
對于靜態(tài)方法可以直接調(diào)用仇奶。
語法規(guī)則為 類名.方法名(參數(shù))
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class A
{
public static void F() => WriteLine("靜態(tài)方法");
public void FF() => WriteLine("實例方法");
}
static void Main(string[] args)
{
A.F();
var b = new A();
b.FF();
ReadKey();
}
}
}
關(guān)于靜態(tài)方法與實例方法區(qū)別
靜態(tài)方法需要使用 static 修飾貌嫡,實例方法不用。
靜態(tài)方法不需要進行創(chuàng)建對象直接就可以調(diào)用该溯,實例方法需要創(chuàng)建對象岛抄。
實例方法可以訪問類中的任何成員,而靜態(tài)方法只能訪問靜態(tài)成員狈茉。
對于類的每個實例都有自己的實例方法夫椭,共享靜態(tài)方法屬于類本身,所有實例共享氯庆。
靜態(tài)方法效率上要比實例化高蹭秋,靜態(tài)方法的缺點是不自動進行銷毀,而實例化的則可以做銷毀堤撵。
方法的重載
重載就是對方法的多態(tài)性體現(xiàn)之一仁讨,對于相同方法名的方法,通過改變參數(shù)實現(xiàn)對同名方法的不同操作实昨。
方法的一個版本有不同的簽名洞豁,即方法名相同,但是參數(shù)個數(shù)和/或數(shù)據(jù)類型不同。
實現(xiàn)方法的重載只需要聲明同名但不同參的方法即可丈挟。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class A
{
public int F()//無參數(shù)
{
return 777;
}
public int F(int x)//一個整形參數(shù)
{
return x;
}
public string F(string x)//一個字符串參數(shù)
{
return x;
}
public string F(string x1,string x2)//兩個字符串參數(shù)
{
return x1 + x2;
}
}
static void Main(string[] args)
{
ReadKey();
}
}
}
屬性
屬性是一個方法或一對方法刁卜,對于客戶端來說是一段代碼。
其目的為字段的讀寫屬性標注礁哄。
屬性是一個訪問器长酗,包含讀 get 和寫 set。
屬性可以為私有字段提供外部訪問桐绒。
get 訪問器不帶任何參數(shù)夺脾,且返回屬性聲明的類型。
set 訪問器不應(yīng)該指定任何顯示的參數(shù)茉继,但比以前會假定它帶有一個參數(shù)咧叭,其類型也與屬性相同,表示為value烁竭。
private int age;//私有字段age
public int Age//公有字段Age菲茬,為私有字段提供訪問
{
get { return age; }//讀取age
set { age = value; }//設(shè)置age的值
}
自動實現(xiàn)屬性
如果屬性的 get 和 set 中不存在其他邏輯,就可以自動實現(xiàn)屬性派撕,這種屬性會自動實現(xiàn)讀寫婉弹。
public int Age {get;set;}
編譯器會自動生成其字段的私有字段,但是無法直接訪問终吼,因為我們不知道編譯器自動生成的名稱镀赌。
但這樣的屬性無法驗證屬性的有效性。
public int Age {get;set;} = 42;
自動實現(xiàn)的屬性可以初始化际跪。
修飾屬性
屬性是可以被修飾的商佛,可以在 get 和 set 中添加邏輯和修飾符。
private int age;
public int Age
{
get
{
if (age > 100)//為讀取數(shù)據(jù)添加邏輯判斷
{
return 0;
}
else
{
return age;
}
}
private set//更改寫權(quán)限
{
age = value;
}
}
只讀只寫
屬性或索引器至少有一個訪問器姆打。
如果屬性只寫一個 get 就會變成只讀良姆,只寫屬性不能自動實現(xiàn)。
public int X { get; set; }//讀寫都行
public int Y { get; }//只寫
private int z;
public int Z//只寫屬性不能自動生成
{
set { z = value; }
}
事件
事件:基本上說是一個用戶操作幔戏,如按鍵玛追、點擊、鼠標移動等等闲延,或者是一些提示信息豹缀,如系統(tǒng)生成的通知。應(yīng)用程序需要在事件發(fā)生時響應(yīng)事件慨代。例如邢笙,中斷。
C# 中使用事件機制實現(xiàn)線程間的通信侍匙。
事件在類中聲明且生成氮惯,且通過使用同一個類或其他類中的委托與事件處理程序關(guān)聯(lián)叮雳。包含事件的類用于發(fā)布事件。這被稱為 發(fā)布器(publisher) 類妇汗。其他接受該事件的類被稱為 訂閱器(subscriber) 類帘不。事件使用 發(fā)布-訂閱(publisher-subscriber) 模型。
發(fā)布器(publisher) 是一個包含事件和委托定義的對象杨箭。事件和委托之間的聯(lián)系也定義在這個對象中寞焙。發(fā)布器(publisher)類的對象調(diào)用這個事件,并通知其他的對象互婿。
訂閱器(subscriber) 是一個接受事件并提供事件處理程序的對象捣郊。在發(fā)布器(publisher)類中的委托調(diào)用訂閱器(subscriber)類中的方法(事件處理程序)。
具體內(nèi)容暫時略
索引器
索引器(Indexer) 允許一個對象可以像數(shù)組一樣被索引慈参。為類定義一個索引器時,該類的行為就會像一個 虛擬數(shù)組(virtual array) 一樣驮配∧锢可以使用數(shù)組訪問運算符([ ])來訪問該類的實例。
具體內(nèi)容暫時略
運算符
在類中可以對運算符重載壮锻,使用關(guān)鍵字 operator 琐旁。
可以使用用戶自定義類型的運算符。重載運算符是具有特殊名稱的函數(shù)猜绣,是通過關(guān)鍵字 operator 后跟運算符的符號來定義的旋膳。與其他函數(shù)一樣,重載運算符有返回類型和參數(shù)列表途事。
其語法為 :
返回類型 operator 運算符 (參數(shù))
{
return 返回值
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
int weight;//字段重量
public MyClass(int weight)//構(gòu)造函數(shù)
{
this.weight = weight;
}
public static int operator - (MyClass a, MyClass b)//對運算符減號進行了更改
//將其更改為返回相加的和
{
return a.weight + b.weight;
}
}
static void Main(string[] args)
{
MyClass myClass1 = new MyClass(500);
MyClass myClass2 = new MyClass(200);
Console.Write(myClass1 - myClass2);//700
ReadKey();
}
}
}
構(gòu)造函數(shù)
構(gòu)造函數(shù)分為三類: 實例構(gòu)造函數(shù) 、靜態(tài)構(gòu)造函數(shù) 和 私有構(gòu)造函數(shù)擅羞。
構(gòu)造函數(shù)是類的一種特殊方法尸变,每次創(chuàng)建類的實例都會調(diào)用它。在創(chuàng)建一個類的實例時减俏,構(gòu)造函數(shù)就像一個方法一樣被調(diào)用召烂,但不返回值。
其語法為:
public class MyClass
{
public MyClass()
{
}
}
一般情況下娃承,如果沒有提供任何構(gòu)造函數(shù)奏夫,編譯器會在后臺默認生成一個構(gòu)造函數(shù)。
將所有成員字段初始化為標準的默認值历筝。
默認值引用類型為空酗昼,數(shù)值類型為0,布爾類型為false梳猪。
如果為構(gòu)造函數(shù)提供參數(shù)麻削,參數(shù)為成員字段。編譯器將不會自動提供默認的構(gòu)造函數(shù),編譯器會假定這是唯一可用的默認呛哟,其他未列入?yún)?shù)的成員字段將不會初始化為默認值叠荠。
一個類中可以有多個構(gòu)造函數(shù),且構(gòu)造函數(shù)可以重載
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
public int a;
public int b;
public int c;
public int d;//沒有構(gòu)造函數(shù)扫责,無法實例化
public MyClass(int a)//聲明a的構(gòu)造函數(shù) {
a = 0;
}
public MyClass(int b,int c)//構(gòu)造函數(shù)重載
{
b = 0;
c = 10;//設(shè)置初始值
}
}
static void Main(string[] args)
{
ReadKey();
}
}
}
···
在聲明了傳入?yún)?shù)的構(gòu)造函數(shù)后榛鼎,生成實例對象時需要傳入?yún)?shù)。
···using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
public int a;
public int b;
public MyClass(int a,int b)
{
a = 0;
b = 0;
}
}
static void Main(string[] args)
{
var s = new MyClass(1,2);
WriteLine($"{s.a} {s.b}");//0 0
//創(chuàng)建初始化對象鳖孤,但是傳入?yún)?shù)沒有對a者娱,b賦值,所以a,b現(xiàn)在還是0
s.a = 100;
s.b = 777;
WriteLine($"{s.a} {s.b}");//100 777
ReadKey();
}
}
}
實例構(gòu)造函數(shù)
使用 new 表達式創(chuàng)建類的對象或者結(jié)構(gòu)(例如int)時淌铐,會調(diào)用其構(gòu)造函數(shù)肺然。并且通常初始化新對象的數(shù)據(jù)成員。 new 關(guān)鍵字調(diào)用構(gòu)造函數(shù)腿准。
構(gòu)造函數(shù)可以有參數(shù)际起,可以以重載的形式存在多個構(gòu)造函數(shù)。
除非類是靜態(tài)的吐葱,否則會為沒有構(gòu)造函數(shù)的類街望,自動生成一個默認構(gòu)造函數(shù),并使用默認值來初始化對象字段弟跑。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
public int a;
public int b;
public MyClass(int a, int b)
{
this.a = a;//this 關(guān)鍵字表示當前對象灾前,可以在創(chuàng)建實例對象時傳入?yún)?shù)直接賦值
this.b = b;
}
}
static void Main(string[] args)
{
var x = new MyClass(1,10);
WriteLine(x.a);//0
WriteLine(x.b);//10
ReadKey();
}
}
}
this 關(guān)鍵字表示當前對象,可以在創(chuàng)建實例對象時傳入?yún)?shù)直接賦值,避免了直接剛剛初始化默認值后傳入?yún)?shù)無效孟辑。
構(gòu)造函數(shù)也可以不傳入?yún)?shù)哎甲。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
public int a;
public int b;
public MyClass()
{
this.a = a;
this.b = b;
}
}
static void Main(string[] args)
{
var x = new MyClass();//無參數(shù),直接使用默認值
WriteLine(x.a);//0
WriteLine(x.b);//0
ReadKey();
}
}
}
這里直接輸出默認值0饲嗽。
靜態(tài)構(gòu)造函數(shù)
可以給類編寫無參數(shù)的靜態(tài)構(gòu)造函數(shù)炭玫,這種構(gòu)造函數(shù)只執(zhí)行一次。
編寫靜態(tài)函數(shù)是為了類中的靜態(tài)字段或?qū)傩孕枰獜耐獠砍跏蓟@些靜態(tài)字段和屬性貌虾。
靜態(tài)函數(shù)無法預(yù)計在某時某刻以什么順序執(zhí)行吞加。
但是可以確保靜態(tài)函數(shù)之多運行一次。通常在第一次調(diào)用類的任何成員之前執(zhí)行靜態(tài)函數(shù)尽狠。
靜態(tài)構(gòu)造函數(shù)沒有任何訪問修飾符衔憨,也不能帶有任何參數(shù),一個類中只能有一個靜態(tài)構(gòu)造函數(shù)袄膏。
無參數(shù)實例構(gòu)造函數(shù)和靜態(tài)構(gòu)造函數(shù)在一個類中定義践图。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
public static int a;
public MyClass()//實例構(gòu)造函數(shù)
{
a = 100;
}
static MyClass()//靜態(tài)構(gòu)造函數(shù)
{
a = 777;
}
}
static void Main(string[] args)
{
WriteLine(MyClass.a);//777
var x = new MyClass();
WriteLine(MyClass.a);//100
ReadKey();
}
}
}
這里首先輸出777,在類中其他成員執(zhí)行前先執(zhí)行靜態(tài)構(gòu)造函數(shù)沉馆,然后生成實例對象平项,實例執(zhí)行構(gòu)造函數(shù)赫舒,使其值變成100。
私有構(gòu)造函數(shù)
私有構(gòu)造函數(shù)是一種特殊的實例構(gòu)造函數(shù)闽瓢。 它通常用于只包含靜態(tài)成員的類中(保證該類不會被實例化)接癌。 如果類具有一個或多個私有構(gòu)造函數(shù)而沒有公共構(gòu)造函數(shù),則無法創(chuàng)建該類的實例扣讼。聲明空構(gòu)造函數(shù)可阻止自動生成默認構(gòu)造函數(shù)缺猛。
如果不聲明公有,則默認為私有構(gòu)造函數(shù)椭符。
私有構(gòu)造函數(shù)無法被實例化荔燎。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp6
{
class Program
{
public class MyClass
{
public static int a = 100;
private MyClass() { }//用空的私有構(gòu)造函數(shù)使其無法實例化
}
static void Main(string[] args)
{
var x = new MyClass();//會報錯,Program.MyClass.MyClass()”不可訪問销钝,因為它具有一定的保護級別
ReadKey();
}
}
}
析構(gòu)函數(shù)
析構(gòu)函數(shù)只能存在于類中有咨,析構(gòu)函數(shù)不存在任何修飾符,沒有參數(shù)蒸健,也就是不能對析構(gòu)函數(shù)重載座享。
析構(gòu)函數(shù)在對象被垃圾回收器回收時調(diào)用。
析構(gòu)函數(shù)的名字由符號“~”加類名組成似忧。
public class Myclass
{
~Myclass()
{
}
}
一個類只能有一個析構(gòu)函數(shù)渣叛,沒有修飾符,沒有參數(shù)盯捌,沒有返回值淳衙。
析構(gòu)函數(shù)與構(gòu)造函數(shù)區(qū)別
構(gòu)造函數(shù)是在創(chuàng)建對象時,使用給定的值將對象初始化饺著。
析構(gòu)函數(shù)用于釋放對象箫攀,根據(jù)內(nèi)存清楚策略執(zhí)行。
類型
匿名類型
匿名類是繼承自object且沒有名稱的類幼衰,類的定義從初始化器中推斷靴跛。
創(chuàng)建匿名類型使用 var 和 new 關(guān)鍵字。
···
···
訪問修飾符
說明 | 解釋 |
---|---|
public | 聲明公有成員塑顺,訪問不受限制,允許從外部訪問俏险。 |
private | 聲明私有成員严拒,只有該類中的成員可以訪問,如果在聲明中沒有設(shè)置訪問修飾符竖独,則默認是private裤唠。 |
protected | 聲明受保護成員,包含類和包含類派生的類可以訪問 莹痢,對外界是隱藏的种蘸。 |
internal | 聲明內(nèi)部成員皮服,只能當前程序集可以訪問恩伺。 |
protected internal | 聲明受保護的內(nèi)部成員,只能訪問當前程序集和包含類派生的類。 |
只讀成員
如果不希望初始化化后修改數(shù)據(jù)成員裹纳,可以使用 readonly 修飾符。
只讀字段:帶有 readonly 修飾符的字段只能在構(gòu)造函數(shù)中分配值讳苦。
不用與常量芒炼,只讀字段可以是實例成員。使用只讀字段作為類成員時滨彻,需要將static 分配給該字段藕届。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
class MyClass
{
public readonly static int x;
}
static void Main(string[] args)
{
MyClass.x = 100;//報錯
WriteLine(MyClass.x);
ReadKey();
}
}
}
在主函數(shù)中對x賦值時會報錯。
無法對靜態(tài)只讀字段賦值(靜態(tài)構(gòu)造函數(shù)或變量初始值除外)亭饵。
{
public readonly static int x;
static MyClass()
{
x = 777;
}
}
class MyClass
{
public readonly static int x = 100;
}
}
用靜態(tài)構(gòu)造函數(shù)賦值休偶,或者定義時直接賦值。
如果類型包含可以改變的成員辜羊,它就是一個可變類型踏兜,使用 readonly 修飾符會報錯。
狀態(tài)只能在構(gòu)造函數(shù)中初始化只冻,如果對象沒有任何可以改變的成員庇麦,只有只讀成員,那么就是一個不可變類型喜德。
其內(nèi)容只能在初始化時設(shè)置山橄。
字段屬性
最簡單的寫法就是
public int x {get;}
省略 set 訪問器。變成只讀屬性舍悯。
自動創(chuàng)建只讀屬性航棱。
public string id = Guid.NewGuid().ToString();
等號后面為此生GUID實例,返回值萌衬。
匿名類型
var 關(guān)鍵字用于表示隱式類型化的變量饮醇,和 new 一起使用的時候可以創(chuàng)建匿名類型。
匿名類型只是一個繼承自object且沒有名稱的類秕豫。
編譯器為類型偽造一個名稱朴艰,只有編譯器才能使用它。
var asdw = new
{
a = "111";
b = "222";
c = "333"
}
var qwe = new
{
a = "999";
b = "888";
c = "777"
}
這里的asdw和qwe的類型就是相同的混移§羰可以設(shè)置相等。
asdw = qwe;
結(jié)構(gòu)
結(jié)構(gòu)實際上將數(shù)據(jù)項組合在一起歌径,大多數(shù)情況用public
類存儲在堆中毁嗦,數(shù)據(jù)在生存周期上有很大靈活性,但是性能會有一定損耗回铛。
相對于的狗准,可以使用結(jié)構(gòu)克锣。
結(jié)構(gòu)和類的語法大致相同。但也有許多不同腔长。
結(jié)構(gòu)可帶有方法袭祟、字段、索引饼酿、屬性榕酒、運算符方法和事件。
例如故俐,結(jié)構(gòu)的定義使用關(guān)鍵字 struct
public struct MyStruct
{
public int x1;
public int x2;
}
public class MyClass
{
public int x1;
public int x2;
}
機構(gòu)和類的區(qū)別
結(jié)構(gòu)是值類型想鹰,類是引用類型。
結(jié)構(gòu)存儲在棧上药版,類存儲在堆上辑舷,棧中保存的只是引用。
結(jié)構(gòu)不支持繼承槽片,類支持繼承何缓。
結(jié)構(gòu)不能聲明默認的構(gòu)造函數(shù)。
結(jié)構(gòu)可實現(xiàn)一個或多個接口还栓。
結(jié)構(gòu)成員不能指定為 abstract碌廓、virtual 或 protected。
結(jié)構(gòu)體中聲明的字段無法賦予初值剩盒,類可以谷婆。
結(jié)構(gòu)體的構(gòu)造函數(shù)中,必須為結(jié)構(gòu)體所有字段賦值辽聊,類的構(gòu)造函數(shù)無此限制纪挎。
使用場景
當堆棧的空間很有限,且有大量的邏輯對象時跟匆,創(chuàng)建類要比創(chuàng)建結(jié)構(gòu)好一些异袄。
在表現(xiàn)抽象和多級別的對象層次時,類是最好的選擇玛臂,因為結(jié)構(gòu)不支持繼承烤蜕。
需要為每個對象分配內(nèi)存,在這種情況下迹冤,使用結(jié)構(gòu)的成本較低讽营; 用于小的數(shù)據(jù)結(jié)構(gòu)。
結(jié)構(gòu)是值類型
雖然是值類型叁巨,但是可以當做類處理斑匪。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
public struct MyStruct
{
public int x1;
public int x2;
}
static void Main(string[] args)
{
MyStruct a = new MyStruct();
a.x1 = 100;
a.x2 = 777;
WriteLine(a.x1);
WriteLine(a.x2);
ReadKey();
}
}
}
這里的 new運算符不分配內(nèi)存呐籽,而只是調(diào)用相應(yīng)的構(gòu)造函數(shù)锋勺。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
public struct MyStruct
{
public int x1;
public int x2;
}
static void Main(string[] args)
{
MyStruct a;
a.x1 = 100;
a.x2 = 777;
WriteLine(a.x1);
WriteLine(a.x2);
ReadKey();
}
}
}
將 new 去掉也是合法蚀瘸。
因為結(jié)構(gòu)是值類型,聲明變量a是為結(jié)構(gòu)在棧中分配空間庶橱。所以可以為其賦值贮勃。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
public struct MyStruct
{
public int x1;
public int x2;
}
static void Main(string[] args)
{
MyStruct a;
int s = a.x2;
s = 100;
WriteLine(s);
ReadKey();
}
}
}
這里將會報錯,原因出在 int s = a.x2;苏章。
結(jié)構(gòu)遵循其他數(shù)據(jù)類型都遵守的規(guī)則:所有元素在使用前都要初始化寂嘉。
結(jié)構(gòu)調(diào)用 new 運算符或者給所有字段賦值,結(jié)構(gòu)就完全初始化了枫绅。
如果結(jié)構(gòu)定義類的成員字段泉孩,在初始化包含對象時,該結(jié)構(gòu)就會初始化為0并淋。
結(jié)構(gòu)會影響性能的值類型寓搬,根據(jù)結(jié)構(gòu)的使用方式可能是正面的也可能是負面的。
正面:為結(jié)構(gòu)分配內(nèi)存時县耽,速度非尘渑纾快,因為他們保存在內(nèi)聯(lián)或棧中兔毙,在結(jié)構(gòu)超出作用域被刪除時也十分快唾琼,不需要等待了解回收。
負面:只要把結(jié)構(gòu)作為參數(shù)傳遞時或賦值給另一個結(jié)構(gòu)時澎剥,結(jié)構(gòu)的所有內(nèi)容都會被復(fù)制锡溯。而對于類只是復(fù)制引用。
把結(jié)構(gòu)作為參數(shù)傳遞給方法時肴裙,應(yīng)該作為 ref 參數(shù)傳遞趾唱。
此時只傳遞結(jié)構(gòu)在內(nèi)存中的地址,但是被調(diào)用的方法可以改變機構(gòu)的值蜻懦。
結(jié)構(gòu)和繼承
結(jié)構(gòu)不能繼承甜癞。
唯一例外的是所有結(jié)構(gòu)都派生與system object。
因此結(jié)構(gòu)可以訪問 system object 的方法宛乃。
結(jié)構(gòu)的構(gòu)造函數(shù)
為結(jié)構(gòu)定義構(gòu)造函數(shù)的方法和為類定義構(gòu)造函數(shù)的方法相同悠咱。
默認構(gòu)造函數(shù)把所有數(shù)值字段都初始化為0,且總是隱式的給出征炼。
結(jié)構(gòu)的構(gòu)造函數(shù)需要初始化每個數(shù)據(jù)成員析既。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
public struct MyStruct
{
public int x1;
public int x2;
public MyStruct(int x1, int x2)//為每個成員初始化
{
this.x1 = x1;
this.x2 = x2;
}
}
static void Main(string[] args)
{
ReadKey();
}
}
}
按值按參數(shù)傳遞參數(shù)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
public struct A
{
public int X;
public A(int x)
{
X = x;
}
}
public static void ChangeA(A a)
{
a.X = 2;
}
static void Main(string[] args)
{
A a1 = new A(1);
ChangeA(a1);
WriteLine(a1.X);//1
ReadKey();
}
}
}
最后得到的結(jié)果為1,ChangA方法傳入?yún)?shù)a1谆奥,而這個a1是一個值眼坏,是棧中變量的a一個副本,只會將a1.X變成2.酸些。而對于原本的a.X沒有影響宰译。
如果A是類檐蚜,則會傳入引用,a1得到的是內(nèi)存地址沿侈,直接對a操作闯第。
如果要傳入結(jié)構(gòu)的引用,可以使用 ref 關(guān)鍵字
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
class Program
{
public struct A
{
public int X;
public A(int x)
{
X = x;
}
}
public static void ChangeA(ref A a)
{
a.X = 2;
}
static void Main(string[] args)
{
A a1 = new A(1);
ChangeA(ref a1);
WriteLine(a1.X);//2
ReadKey();
}
}
}
在ChangeA函數(shù)的參數(shù)前面指明要傳入引用缀拭,所以在傳入?yún)?shù)時也要指定是ref咳短。
c#對傳遞給方法的參數(shù)必須要求初始化,無論是值還是引用
如果方法返回一個值蛛淋,該方法通常聲明返回類型咙好,如果方法返回多個值,可能類型還不相同褐荷。有三種解決方法敷扫。
1.聲明類和結(jié)構(gòu),將返回的所有信息都定義為該類型的成員诚卸。
2.使用元祖類型葵第。
3.選用 out 關(guān)鍵字。
out關(guān)鍵字會導(dǎo)致參數(shù)通過引用來傳遞合溺。這與 ref 關(guān)鍵字類似卒密,不同之處在于 ref 要求變量必須在傳遞之前進行初始化。
out參數(shù)不能初始化并且必須在方法返回之前賦值而ref參數(shù)必須初始化棠赛。
若要使用 out參數(shù)哮奇,方法定義和調(diào)用方法都必須顯式使用 out 關(guān)鍵字。例如:
class Outt
{
static void Method(out int i)
{
i=44;
}
static void Main()
{
Method(out value);
}
ref 和 out 關(guān)鍵字在運行時的處理方式不同睛约,但在編譯時的處理方式相同鼎俘。因此,如果一個方法采用 ref 參數(shù)辩涝,而另一個方法采用 out 參數(shù)贸伐,則無法重載這兩個方法。
但是怔揩,如果一個方法采用 ref 或 out 參數(shù)捉邢,而另一個方法不采用這兩類參數(shù),則可以進行重載商膊。
屬性不是變量伏伐,因此不能作為 out 參數(shù)傳遞。
可空類型
引用類型可以為空晕拆,而值類型不能為空藐翎。
可空類型只需要在需要的類型后面添加 ?
int? a = null;
對于可空類型,可以使用基本類型的運算符。
枚舉
枚舉是值類型吝镣,包含一組命名的常量赚导,,默認類型為int赤惊,常量的值默認從0開始遞增,可以改為其他值凰锡,但總是遞增的未舟,
使用 ** enum** 關(guān)鍵字
public enum f
{
q,
w,
e
}
可以更改為其他類型
public enum f:short
{
q,
w,
e
}
部分類
partial 允許把類,結(jié)構(gòu)掂为,方法或接口放在多個文件中裕膀。
partial 有助于把類分開放在兩個文件中,而不對代碼進行生成器定義的文件進行修改勇哗。
partial 用法是把 partial 放在class昼扛,struts或 interface關(guān)鍵字前面。
//asdw.cs
partial class MyClass1
{
}
//qwe/cs
partial class MyClass2
{
}
編譯包含這兩個源文件的項目時會創(chuàng)建一個 SampleClass 類欲诺,包含兩個方法抄谐, MyClass1() 和 MyClass2() 。
如果聲明了以下關(guān)鍵字扰法,則這些關(guān)鍵字就必須應(yīng)用于同一個類的所有部分蛹含。
public private protected internal abstract sealed new 一般約束
在嵌套的類型中,只要 partial 關(guān)鍵字位于class關(guān)鍵字前面塞颁,就可以嵌套部分類浦箱。
把嵌套了編譯到類型中,屬性祠锣,XML注釋酷窥,接口,泛型的參數(shù)屬性和成員會合并伴网。
盡管 partial 關(guān)鍵字可以很容易創(chuàng)建跨過多個文件巨大的類蓬推,但最好把大類拆分為小類,一個類自用于一個目的澡腾。
部分類可以包含部分方法拳氢,如果生成的代碼應(yīng)該調(diào)用可能不存在的方法,這就是非常有用的蛋铆,擴展部分類的人員可以決定創(chuàng)建部分方法的自定義實現(xiàn)方法馋评,或者什么都不做。
部分方法的實現(xiàn)可以放在部分類的任何其他地方刺啦。部分方法必須是void類型留特,否則編譯器在沒有實現(xiàn)代碼的情況下無法刪除調(diào)用。
擴展方法
擴展方法使你能夠向現(xiàn)有類型“添加”方法,而無需創(chuàng)建新的派生類型蜕青、重新編譯或以其他方式修改原始類型苟蹈。擴展方法被定義為靜態(tài)方法,但它們是通過實例方法語法進行調(diào)用的右核。它們的第一個參數(shù)指定該方法作用于哪個類型慧脱,并且該參數(shù)以 this修飾符為前綴。
繼承就是給對象添加功能的好方法贺喝,擴展方法是給對象添加功能的另一個選項菱鸥。
在不能繼承時也可以使用這個方法,例如類是密封的躏鱼。
擴展方法也可以用于擴展接口氮采,這樣,實現(xiàn)接口的所有類就有了公共功能染苛。
擴展方法是靜態(tài)鹊漠,是類的一部分,但實際上沒有放在類的源代碼中茶行。
即使擴展方法是靜態(tài)躯概,也要使用標準的實例方法語法,在后臺編譯器會把它改為靜態(tài)方法畔师。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;
namespace ConsoleApp8
{
public static class Extension // 必須是一個靜態(tài)類
{
public static void SayHello(this string str) //必須為public static 類型
//且參數(shù)使用this關(guān)鍵字
{
if (str == null)
{
Console.WriteLine("Hello");
}
else
Console.WriteLine("{0}", str);
}
}
class Program
{
static void Main(string[] args)
{
string str = null;
str.SayHello();
string str1 = "not hello";
str1.SayHello();
Console.ReadKey();
}
}
}
這樣的話在同一個命名空間下的所有string都可以使用SayHello方法了.
首先聲明擴展方法的類必須是static類楞陷,并且方法也要是static類型,擴展方法必須包含this關(guān)鍵字作為它的第一個參數(shù)類型茉唉,并且后面跟著它所擴展的類的名稱.
this 關(guān)鍵字必須匹配類型的擴展方法固蛾,而且需要打開定義擴展的靜態(tài)方法的名稱空間。
如果類型還定義了同名的實例方法度陆,擴展方法就永遠不會使用艾凯,類中的已有實例方法都優(yōu)先。
當多個同名的擴展方法擴展相同的類型懂傀,編譯器無法在多個實現(xiàn)代碼中選擇趾诗,但是如果調(diào)用代碼在同一個名稱空間時,這個名稱空間就優(yōu)先蹬蚁。
object類
**所有的.Net類都最終派生于system object恃泪。
在定義類時沒有指定基類就會自動假定這個類派生與system object。
對于結(jié)構(gòu)犀斋,派生是間接的贝乎。
結(jié)構(gòu)總是派生與system vauletype,而system vauletype 又派生與system object叽粹。
tostring() 獲取當前對象字符串的快捷方式览效。
gethashcode() 獲取映射
equals()和referenceequals() 等價性比較却舀。
finalize() 垃圾回收
gettype() 獲取類型
memberwiseclone() 淺復(fù)制