鍍金池/ 教程/ C/ C#中一些易混淆概念總結(jié)-數(shù)據(jù)類型存儲位置,方法調(diào)用,out和ref參數(shù)的使用
解析接口
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)類

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

這幾天一直在復(fù)習C#基礎(chǔ)知識,過程中也發(fā)現(xiàn)了自己以前理解不清楚和混淆的概念?,F(xiàn)在給大家分享出來我的筆記:

一,.NET平臺的重要組成部分都是有哪些

1)FCL (所謂的.NET框架類庫)

這些類是微軟事先定義好的。

例如當我們新創(chuàng)建一個windows窗體應(yīng)用程序是,VS會幫我們自動生成下面的代碼:

using System;
using System.Collections.Generic;
using System.Text;

這些就是微軟事先為程序員定義好的類庫。程序員可以直接使用的。

2)CLR (所謂的公共語言運行時)

創(chuàng)建部署.NET程序的必備環(huán)境

使用C#,F(xiàn)#,VB等語言都可以來創(chuàng)建.NET應(yīng)用程序。這時候就需要一個公共語言規(guī)范,來把不同的語言解釋成.NET FramWork認識的東西。

二,什么是程序集

程序集主要有MSIL組成(所謂的微軟中間語言,主要由dll文件組成)

不同編程語言程序被.NET FrameWork編譯成程序集(dll文件),當程序需要被執(zhí)行時,通過CLR中的JIT(及時編譯器)編譯成本地代碼,并將指令發(fā)送給CPU執(zhí)行。

程序集一般有兩種:.dll和.exe文件(但是不是所有的dll和exe都叫程序集)

比如:我們在同一個解決方案下,建立多個應(yīng)用程序或者類庫文件。這些程序或者類庫編譯后就會變成不同的程序集。他們之間是相互獨立的。之間如果想要相互訪問,需要添加引用。

三,Parse轉(zhuǎn)換和Convert轉(zhuǎn)換的區(qū)別

1)Parse轉(zhuǎn)換

①Parse轉(zhuǎn)換只能轉(zhuǎn)換字符串

②自變量是指定的數(shù)據(jù)類型才可以轉(zhuǎn)換成功

下面的是.NET Reflector編譯的源代碼

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

2)Convert轉(zhuǎn)換

①可以轉(zhuǎn)換其他類型(如:類)

②與Parse的區(qū)別就是,轉(zhuǎn)換前會對被轉(zhuǎn)換的對象進行判斷,如果對象為null則會轉(zhuǎn)換失敗

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

下面是實例源代碼:

class Program
    {
        static void Main(string[] args)
        {
            string a = Console.ReadLine();
            //Parse只可以轉(zhuǎn)換字符串
            int b = Int32.Parse(a);

            //Convert可以轉(zhuǎn)換類等對象
            ParseNumber parNum = new ParseNumber();
            //這種寫法編譯器會報錯
            //int b = Int32.Parse(parNum);
            int c = Convert.ToInt32(parNum);

            Console.WriteLine(b);
            Console.WriteLine(b.GetType());

            Console.ReadKey();
        }
    }

    class ParseNumber
    {
        private int nunm;
        public int Num { get; set; }
    }

四,數(shù)據(jù)類型的存儲位置

1)存儲在棧中的數(shù)據(jù)類型

所有數(shù)值類型,char,bool,枚舉,結(jié)構(gòu)體

2)存儲在堆中

string,數(shù)組,類

管這些類型,他們的變量的聲明都是保存在棧里,真實的對象保存在堆里面,棧里面的變量存儲打的是對象的地址。

下面以數(shù)組來簡單說一下這個問題:

       //聲明一個一維數(shù)組
            int[] arr = new int[4];

那么這個表達式的執(zhí)行順序是什么呢?

①首先程序會在棧中開辟一段名為arr的int[]類型的空間

②然后在堆中開辟一個int[]對象,再該對象中會有4塊連續(xù)的內(nèi)存空間

③堆中的對象返回類型為地址,即new int[4]表達式返回的是地址

示意圖如下:

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

五,C#方法調(diào)用

1)在C#中我們可以給參數(shù)傳遞默認值,所以當我們調(diào)用這個方法的時候,可以不給這個參數(shù)傳遞值

static void Main(string[] args)
        {
            //聲明一個一維數(shù)組
            int[] arr = new int[4];
            Program pro = new Program();  
       //直接調(diào)用,沒有傳遞參數(shù)值
            pro.para();

        }
        public void para(int i=5)
        {
            Console.WriteLine(i);
            Console.ReadKey();
        }

2)帶默認參數(shù)的方法,默認值必須放在最右側(cè)

下面的寫法編譯器會報錯

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

3)方法的可變參數(shù)

①可變參數(shù)被Params

②Params只能用來修飾一維數(shù)組

static void Main(string[] args)
        {
            //聲明一個一維數(shù)組
            int[] arr = new int[4];

            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = i;
            }
            Program pro = new Program();
            pro.para();
            //傳遞一位數(shù)組arr
            pro.param(arr);

            Console.ReadKey();
        }
        //params用來修飾一維數(shù)組
        public void param(params int[] arr)
        {
            foreach (var item in arr)
            {
                Console.WriteLine(item);
            }
        }

③給可變參數(shù)賦值的時候可以直接傳遞數(shù)組元素

       //聲明一個一維數(shù)組
            int[] arr = new int[4];

            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = i;
            }
            Program pro = new Program();
            pro.para();
            //傳遞一位數(shù)組arr
            pro.param(arr);
            //直接傳遞數(shù)組元素,調(diào)用時會自動將這些數(shù)封裝成數(shù)組,并將數(shù)組傳遞
            pro.param(0, 1, 2, 3);

            Console.ReadKey();

④與默認參數(shù)一樣,可變參數(shù)的聲明必須放在方法參數(shù)的最后

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

4)方法的out和ref參數(shù)

①out參數(shù)側(cè)重于輸出,必須在方法內(nèi)對其賦值

如下圖的聲明編譯器會報錯

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

正確的使用方法

       static void Main(string[] args)
        {
            //聲明參數(shù)m
            int m=0;
            Program pro = new Program();
            //傳遞參數(shù)m,必須帶有out參數(shù)標識
            pro.outPara( out m);
            Console.WriteLine(m);
            Console.ReadKey();
        }

        //out參數(shù)側(cè)重于輸出,必須在方法內(nèi)對其賦值
        public void outPara(out int i)
        {
            //方法內(nèi)部必須對out參數(shù)進行賦值
            i=5;
        }

②ref參數(shù)側(cè)重于修改,但是也可以不修改參數(shù)的值

static void Main(string[] args)
        {
            //聲明參數(shù)m
            int m=0;
            Program pro = new Program();
            //傳遞參數(shù)m,必須帶有out參數(shù)標識
            pro.outPara( out m);  
       //ref參數(shù)傳遞之前必須對其賦值,因為在方法內(nèi)部可能會用到該參數(shù)
            pro.refPara(ref m);
            //Console.WriteLine(m);
            Console.ReadKey();
        }

        //
        public void refPara(ref int i)
        {
            Console.WriteLine("可以不對參數(shù)i進行任何操作!");
        }

輸出結(jié)果如下:

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

六,屬性易混淆點辨別

①屬性本身不存值,值是存在這個屬性所封裝的字段里面

class Study
    {
        private int nID;

        //屬性的值存儲在封裝的字段里面
        public int NID
        {

            get { return nID; }
            //這里我們給屬性賦值
            set { nID = value; }
        }
    }

通過訪問屬性字段獲取字段的值

       Study stu = new Study();
            //通過訪問屬性字段獲取字段的值
            int nID = stu.NID;

②屬性的返回值類型和字段的值類型沒有關(guān)系

     //屬性的值類型為bool
        private bool gender;
        //字段的返回類型為string
        public string Gender
        {
            get{return gender==true?"男":"女";}
            set{gender =value=="男"?true:false;}
        }

屬性的返回值類型決定了get返回值的類型和set參數(shù)的類型

     //屬性的值類型為bool
        private bool gender;
        //字段的返回類型為string
        public string Gender
        {
            //get的返回值類型為bool
            get{return gender==true?"男":"女";}
            //set參數(shù)類型為bool
            set{gender =value=="男"?true:false;}
        }

③自動屬性到底是怎么回事?

看如下的代碼:

     private string strName;
        //自動屬性封裝strName
        public string StrName
        {
            get;
            set;
        }

這就是所謂的自動屬性封裝字段。在非自動屬性中,程序默認的會有value值來給字段賦值,但是在自動屬性中是怎么賦值的呢?

我們使用.NET Reflector反編譯來看源代碼:

這是我們封轉(zhuǎn)的屬性代碼:

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

反編譯set函數(shù)源代碼:

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

我們可以看到.NET會默認為我們的程序生成一個成員變量k__BackingField

get函數(shù)的源代碼:

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

返回的也是該成員變量;

那么什么時候可以使用自動屬性呢?

如果對一個字段取值和賦值的時候沒有任何邏輯驗證并且可讀可寫的時候,就可以使用自動屬性。

七,C#類聲明易混淆知識點

①首先給大家說明一個問題就是,文件名和類名必須是一樣的么(就是我們在創(chuàng)建類的時候要命明,這個時候會默認的生成一樣的類名稱)?

如圖所示

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

這個是必須的么?

我們嘗試修改類名稱為ChildName,然后訪問類

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

可以看到我們要訪問類,需要通過類名稱訪問而與文件名沒有關(guān)系。

②類表達式的執(zhí)行順序和其意義

編譯器執(zhí)行代碼的時候,

首先會先在棧中開辟一塊類型為Study的內(nèi)存空間放置變量stu

然后在堆中創(chuàng)建該變量的對象

然后調(diào)用該對象的構(gòu)造函數(shù),并且返回該對象在堆中的地址。

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

好吧,到這里,這次的分享就到此結(jié)束了。大家如果閱讀的過程中有什么問題,可以跟我留言交流。