在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ 構(gòu)造函數(shù),this關(guān)鍵字,部分類,枚舉
解析接口
C#中一些易混淆概念總結(jié)-數(shù)據(jù)類型存儲位置,方法調(diào)用,out和ref參數(shù)的使用
解析里氏替換原則,虛方法
繼承
構(gòu)造函數(shù),this關(guān)鍵字,部分類,枚舉
解析Console.WriteLine()
解析抽象類,抽象方法
結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

構(gòu)造函數(shù),this關(guān)鍵字,部分類,枚舉

目錄:

【C#小知識】C#中一些易混淆概念總結(jié)--------數(shù)據(jù)類型存儲位置,方法調(diào)用,out和ref參數(shù)的使用

繼上篇對一些C#概念問題進行細節(jié)的剖析以后,收獲頗多。以前,讀書的時候,一句話一掠而過,但是現(xiàn)在再去重讀的時候,每句話發(fā)現(xiàn)都包含大量的信息。這一篇繼續(xù)總結(jié)自己的學習筆記,給大家深度的剖析一些概念性問題,有助于大家對C#的理解。

一,構(gòu)造函數(shù)

我們先創(chuàng)建一個類,如下面的代碼:

class Program
    {
        static void Main(string[] args)
        {
       
        }
    }
  //創(chuàng)建一個Person類
    class Person
    {

    }

然后生成代碼。

我們使用.NET Reflector反編譯該程序集。會發(fā)現(xiàn)該類一被編譯,CLR會自動的為該類創(chuàng)建一個默認的構(gòu)造函數(shù)。如下圖:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-1.png" alt="" />

所以在創(chuàng)建該對象的時候,會默認的為該類生成一個無參數(shù)的空方法體的構(gòu)造函數(shù)。如果我們不顯式的寫明構(gòu)造函數(shù),CLR會為我們調(diào)用默認的構(gòu)造函數(shù)。

 class Person
    {
        //聲明有實現(xiàn)的構(gòu)造函數(shù)
        public Person()
        {
            Console.WriteLine("我是超人!");
        }
    }

再次反編譯該程序集,會發(fā)現(xiàn)添加的構(gòu)造函數(shù)覆蓋了C#編譯器默認為該類生成的構(gòu)造函數(shù),如下圖:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-2.png" alt="" />

所以,當程序員手動添加了任意類型的構(gòu)造函數(shù),C#編譯器就不會為該類添加默認的構(gòu)造函數(shù)。

構(gòu)造函數(shù)的特點:

①訪問修飾符一般是Public②沒有返回值,方法名與類名稱一致;

二,This關(guān)鍵字的作用

①this關(guān)鍵字代表當前對象,當前運行在內(nèi)存中的那一個對象。我們添加如下的代碼:

private int nAge;

        public int NAge
        {
            get { return nAge; }
            set { nAge = value; }
        }

        //聲明有實現(xiàn)的構(gòu)造函數(shù)
        public Person()
        {
            this.NAge = 100;
            Console.WriteLine("我是超人!");
        }

這時候我們反編譯該程序集,會看到如下結(jié)果:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-3.png" alt="" />

可以看到this關(guān)鍵字代替的就是當前的Person對象。

②this關(guān)鍵字后面跟":"符號,可以調(diào)用其它的構(gòu)造函數(shù)

我們再添加如下的代碼:

        #region 對象的構(gòu)造函數(shù)
        //聲明有實現(xiàn)的構(gòu)造函數(shù)
        public Person()
        {
            this.NAge = 100;
            Console.WriteLine("我是超人!");
        }

        public Person(int nAge)
        {
            Console.WriteLine("超人的年齡{0}", nAge);
        }
     //使用this關(guān)鍵字調(diào)用了第二個一個參數(shù)的構(gòu)造函數(shù)
        public Person(int nAge, string strName)
            : this(1)
        {
            Console.WriteLine("我是叫{0}的超人,年齡{1}", strName, nAge);
        }
        #endregion

我們創(chuàng)建該對象看看是否調(diào)用成功。在Main函數(shù)中添加如下代碼:

Person p = new Person(10,"強子");

我們運行代碼,看到的打印結(jié)果如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-4.png" alt="" />

由結(jié)果我們可以分析出,當含有兩個默認參數(shù)的對象創(chuàng)建的時候應(yīng)該先調(diào)用了一個參數(shù)的構(gòu)造函數(shù)對對象進行初始化,然后有調(diào)用了含有兩個參數(shù)的構(gòu)造函數(shù)對對象進行初始化。

那么到底是不是這個樣子呢?看下邊的調(diào)試過程:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-5.gif" alt="" />

通過上面的調(diào)試過程我們會發(fā)現(xiàn),當構(gòu)造函數(shù)使用this關(guān)鍵字調(diào)用其它的構(gòu)造函數(shù)時,首先調(diào)用的是該調(diào)用的構(gòu)造函數(shù),在調(diào)用被調(diào)用的構(gòu)造函數(shù),先執(zhí)行被調(diào)用的構(gòu)造函數(shù),在執(zhí)行直接調(diào)用的構(gòu)造函數(shù)。

為什么要這個順序執(zhí)行?因為我們默認的傳值是10,我們需要打印的超人的年齡是"10",如果先執(zhí)行直接調(diào)用的構(gòu)造函數(shù),就會被被調(diào)用構(gòu)造函數(shù)覆蓋。

三,部分類

在同一命名空間下可以使用partial關(guān)鍵字聲明相同名稱的類(同一命名空間下默認不允許出現(xiàn)相同的類名稱),叫做部分類或者伙伴類。

如下圖,當在同一命名空間下聲明相同名稱的類,編譯器報錯:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-6.png" alt="" />

當我們使用Partial關(guān)鍵字時,可以順利編譯通過,如下圖:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-7.png" alt="" />

分別添加如下的代碼:

partial class  Person
    {
        private string strAddress;

        public string StrAddress
        {
            get { return strAddress; }
            set { strAddress = value; }
        }
        private string strNumber;

        public string StrNumber
        {
            get { return strNumber; }
            set { strNumber = value; }
        }

        public void Run()
        {

        }
    }

    partial class  Person
    {

        #region 對象屬性
        private int nAge;

        public int NAge
        {
            get { return nAge; }
            set { nAge = value; }
        }

        private string strName;

        public string StrName
        {
            get { return strName; }
            set { strName = value; }
        }

        #endregion

        #region 對象的構(gòu)造函數(shù)
        //聲明有實現(xiàn)的構(gòu)造函數(shù)
        public Person()
        {
            this.NAge = 100;
            Console.WriteLine("我是超人!");
        }

        public Person(int nAge)
        {
            Console.WriteLine("超人的年齡{0}", nAge);
        }

        public Person(int nAge, string strName)
            : this(1)
        {
            Console.WriteLine("我是叫{0}的超人,年齡{1}", strName, nAge);
        }
        #endregion

        public void Sing()
        {

        }
    }

我們再次反編譯該程序集,會發(fā)現(xiàn)如下的結(jié)果:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-8.png" alt="" />

我們會發(fā)現(xiàn)使用Partial關(guān)鍵字的兩個同名類,被編譯成了同一個類。

所以部分類的特點:

①必須在同一個命名空間下的使用Partial關(guān)鍵字的同名類

②部分類其實就是一個類,C#編譯器會把它們編譯成一個類

③在一個伙伴類中定義的變量可以在另一個伙伴類中訪問(因為他們就是一個類)。

四,Const關(guān)鍵字和Readonly關(guān)鍵字的區(qū)別

1)const關(guān)鍵字

在Main函數(shù)中添加如下的代碼:

        const string strName = "強子";
            Console.WriteLine("我的名字叫{0}",strName);

編譯過后,我反編譯該程序集發(fā)現(xiàn)如下結(jié)果:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-9.png" alt="" />

發(fā)現(xiàn)定義的常量并沒有出現(xiàn)在反編譯的代碼中,而且使用Const常量的地方被常量代替了。

2)readonly關(guān)鍵字

添加如下代碼:

class cat
    {
        readonly string reOnlyName = "強子";
        public cat()
        {
            Console.WriteLine(reOnlyName);
        }
    }

生成后反編譯該程序集發(fā)現(xiàn),如下結(jié)果:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-10.png" alt="" />

我們發(fā)現(xiàn)被readonly修飾的變量并沒有被賦值,這是什么回事呢?我們點擊cat類的構(gòu)造函數(shù)時,看到如下結(jié)果:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-11.gif" alt="" />

我們發(fā)現(xiàn)被readonly修飾的變量是在被調(diào)用的時候賦值的。

那么被readonly修飾的變量的是就是不可變的么?當然不是,由反編譯的結(jié)果我們知道,readonly修飾的變量是在被調(diào)用的時候在構(gòu)造函數(shù)中被賦值的,那么我們可以在構(gòu)造函數(shù)中修改readonly的默認值

添加如下代碼:

 class cat
    {
        readonly string reOnlyName = "強子";
        public cat()
        {
            this.reOnlyName = "子強";
            Console.WriteLine(reOnlyName);
        }
    }

在Main()函數(shù)中添加如下的代碼:

運行結(jié)果如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-12.png" alt="" />

說明我們成功在構(gòu)造函數(shù)中修改了readonly變量的值。

readonly和const的區(qū)別:

const常量在聲明的時候就必須賦初始值,這樣聲明變量可以提高程序的運行效率。而readonly變量聲明時可以不賦初始值,但一定要早構(gòu)造函數(shù)中賦初始值。

也就是說,const變量在編譯的時候就要確定常量的值,而readonly是在運行的時候確定該變量的值的。

五,解析枚舉

枚舉的級別和類的級別一樣,可以自定義數(shù)據(jù)類型,可以在枚舉名稱后使用":"來指明枚舉類型??慈缦麓a:

 //定義一個方向的枚舉類型,枚舉成員使用","分割
    enum Direction:string
    {
        east,
        west,
        south,
        north
    }

編譯會報錯,錯誤信息如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-13.png" alt="" />

由此我們可以知道枚舉的數(shù)據(jù)類型是值類型。

因為枚舉是數(shù)據(jù)類型,所以可以直接聲明訪問,如下代碼:

class Program
    {
        static void Main(string[] args)
        {
            //枚舉是數(shù)據(jù)類型可以直接聲明
            Direction dr = Direction.east;

            Console.WriteLine(dr);

            Console.ReadKey();
        }
    }

    //定義一個方向的枚舉類型,枚舉成員使用","分割
    enum Direction
    {
        east,
        west,
        south,
        north
    }

也可以這樣訪問枚舉類型

class Program
    {
        static void Main(string[] args)
        {
            //枚舉是數(shù)據(jù)類型可以直接聲明
           // Direction dr = Direction.east;

            Person p=new Person();
            //直接調(diào)用枚舉變量
            p.dir = Direction.east;
            Console.WriteLine(p.dir);

            Console.ReadKey();
        }
    }

     class Person
    {
        private string strName;
         //直接聲明枚舉變量
        public Direction dir;
    }

每一個枚舉成員都對應(yīng)了一個整型的數(shù)值,這個數(shù)值默認從0開始遞增,可以通過強制轉(zhuǎn)換獲取該枚舉所代表的值。可以通過如下的代碼訪問:

        Direction dr = Direction.east;
            int i = (int)dr;

我們還可以手動為每一個枚舉成員賦值,代表的是整型數(shù)值,賦值后該枚舉成員所代表的值就是所賦的值。如下代碼:

enum Direction
    {
        east=1,
        west=0,
        south=2,
        north=3
    }

將字符串轉(zhuǎn)換成枚舉

       string strDir = "east";
            //將字符串轉(zhuǎn)換成枚舉類型
            Direction d1=(Direction)Enum.Parse(typeof(Direction),strDir);
            //轉(zhuǎn)換的時候忽略大小寫
            Direction d2 = (Direction)Enum.Parse(typeof(Direction), strDir,true);

--------------------------------分割線----------------------------------------

最后我們再來探究一個空指針異常的問題

首先我們先聲明一個Dog類:

class Dog
    {
        private int nAge;

        public int NAge
        {
            get { return nAge; }
            set { nAge = value; }
        }
        private string strName;

        public string StrName
        {
            get { return strName; }
            set { strName = value; }
        }
    }

在Main()函數(shù)中我們這樣調(diào)用

       Dog d = null;
            d.StrName = "旺旺";

結(jié)果會報錯,如下圖

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-14.png" alt="" />

我們已經(jīng)為屬性,封裝字段了,但是為什么沒有辦法給字段賦值呢?我們就來探究一下這個問題。

當我們實例化Dog對象,即

.NET Framwork做了什么工作呢?如下圖:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-15.png" alt="" />

那為什么會報錯呢,原因如下圖:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/2-16.png" alt="" />

這次分享到這里就結(jié)束了。其實蠻享受寫這個過程的。因為在初次的學的時候理解了,如果再寫成博客就又加深了印象,最后希望大家都能養(yǎng)成了良好的學習習慣。