c#類與結(jié)構(gòu)

類:類就是擁有相等功能和相同的屬性的對象的集合。

類是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)屬性
如果屬性的 getset 中不存在其他邏輯,就可以自動實現(xiàn)屬性派撕,這種屬性會自動實現(xiàn)讀寫婉弹。

public int Age {get;set;}

編譯器會自動生成其字段的私有字段,但是無法直接訪問终吼,因為我們不知道編譯器自動生成的名稱镀赌。
但這樣的屬性無法驗證屬性的有效性。

public int Age {get;set;} = 42;

自動實現(xiàn)的屬性可以初始化际跪。

修飾屬性
屬性是可以被修飾的商佛,可以在 getset 中添加邏輯和修飾符。

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)建匿名類型使用 varnew 關(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);
}

refout 關(guān)鍵字在運行時的處理方式不同睛约,但在編譯時的處理方式相同鼎俘。因此,如果一個方法采用 ref 參數(shù)辩涝,而另一個方法采用 out 參數(shù)贸伐,則無法重載這兩個方法。
但是怔揩,如果一個方法采用 refout 參數(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ù)制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锤灿,隨后出現(xiàn)的幾起案子挽拔,更是在濱河造成了極大的恐慌,老刑警劉巖但校,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件螃诅,死亡現(xiàn)場離奇詭異,居然都是意外死亡状囱,警方通過查閱死者的電腦和手機术裸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浪箭,“玉大人,你說我怎么就攤上這事辨绊∧唐埽” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵门坷,是天一觀的道長宣鄙。 經(jīng)常有香客問我,道長默蚌,這世上最難降的妖魔是什么冻晤? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮绸吸,結(jié)果婚禮上鼻弧,老公的妹妹穿的比我還像新娘。我一直安慰自己锦茁,他們只是感情好攘轩,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著码俩,像睡著了一般度帮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上稿存,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天笨篷,我揣著相機與錄音,去河邊找鬼瓣履。 笑死率翅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的袖迎。 我是一名探鬼主播安聘,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痰洒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了浴韭?” 一聲冷哼從身側(cè)響起丘喻,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎念颈,沒想到半個月后泉粉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡榴芳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年嗡靡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窟感。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡讨彼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出柿祈,到底是詐尸還是另有隱情哈误,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布躏嚎,位于F島的核電站蜜自,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏卢佣。R本人自食惡果不足惜重荠,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望虚茶。 院中可真熱鬧戈鲁,春花似錦、人聲如沸嘹叫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽待笑。三九已至鸣皂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暮蹂,已是汗流浹背寞缝。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仰泻,地道東北人荆陆。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像集侯,于是被迫代替她去往敵國和親被啼。 傳聞我的和親對象是個殘疾皇子帜消,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容