這幾天一直在復習C#基礎知識,過程中也發現了自己以前理解不清楚和混淆的概念。現在給大家分享出來我的筆記:
一,.NET平台的重要組成部分都是有哪些
1)FCL (所謂的.NET框架類庫)
這些類是微軟事先定義好的。
例如當我們新創建一個windows窗體應用程序是,VS會幫我們自動生成下面的代碼:
using System; using System.Collections.Generic; using System.Text;
這些就是微軟事先為程序員定義好的類庫。程序員可以直接使用的。
2)CLR (所謂的公共語言運行時)
創建部署.NET程序的必備環境
使用C#,F#,VB等語言都可以來創建.NET應用程序。這時候就需要一個公共語言規范,來把不同的語言解釋成.NET FramWork認識的東西。
二,什么是程序集
程序集主要有MSIL組成(所謂的微軟中間語言,主要由dll文件組成)
不同編程語言程序被.NET FrameWork編譯成程序集(dll文件),當程序需要被執行時,通過CLR中的JIT(及時編譯器)編譯成本地代碼,並將指令發送給CPU執行。
程序集一般有兩種:.dll和.exe文件(但是不是所有的dll和exe都叫程序集)
比如:我們在同一個解決方案下,建立多個應用程序或者類庫文件。這些程序或者類庫編譯后就會變成不同的程序集。他們之間是相互獨立的。之間如果想要相互訪問,需要添加引用。
三,Parse轉換和Convert轉換的區別
1)Parse轉換
①Parse轉換只能轉換字符串
②自變量是指定的數據類型才可以轉換成功
下面的是.NET Reflector編譯的源代碼
2)Convert轉換
①可以轉換其他類型(如:類)
②與Parse的區別就是,轉換前會對被轉換的對象進行判斷,如果對象為null則會轉換失敗
下面是實例源代碼:
class Program { static void Main(string[] args) { string a = Console.ReadLine(); //Parse只可以轉換字符串
int b = Int32.Parse(a); //Convert可以轉換類等對象
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; } }
四,數據類型的存儲位置
1)存儲在棧中的數據類型
所有數值類型,char,bool,枚舉,結構體
2)存儲在堆中
string,數組,類
管這些類型,他們的變量的聲明都是保存在棧里,真實的對象保存在堆里面,棧里面的變量存儲打的是對象的地址。
下面以數組來簡單說一下這個問題:
//聲明一個一維數組
int[] arr = new int[4];
那么這個表達式的執行順序是什么呢?
①首先程序會在棧中開辟一段名為arr的int[]類型的空間
②然后在堆中開辟一個int[]對象,再該對象中會有4塊連續的內存空間
③堆中的對象返回類型為地址,即new int[4]表達式返回的是地址
示意圖如下:
五,C#方法調用
1)在C#中我們可以給參數傳遞默認值,所以當我們調用這個方法的時候,可以不給這個參數傳遞值
static void Main(string[] args) { //聲明一個一維數組
int[] arr = new int[4]; Program pro = new Program();
//直接調用,沒有傳遞參數值 pro.para(); } public void para(int i=5) { Console.WriteLine(i); Console.ReadKey(); }
2)帶默認參數的方法,默認值必須放在最右側
下面的寫法編譯器會報錯
3)方法的可變參數
①可變參數被Params
②Params只能用來修飾一維數組
static void Main(string[] args) { //聲明一個一維數組
int[] arr = new int[4]; for (int i = 0; i < arr.Length; i++) { arr[i] = i; } Program pro = new Program(); pro.para(); //傳遞一位數組arr
pro.param(arr); Console.ReadKey(); } //params用來修飾一維數組
public void param(params int[] arr) { foreach (var item in arr) { Console.WriteLine(item); } }
③給可變參數賦值的時候可以直接傳遞數組元素
//聲明一個一維數組
int[] arr = new int[4]; for (int i = 0; i < arr.Length; i++) { arr[i] = i; } Program pro = new Program(); pro.para(); //傳遞一位數組arr
pro.param(arr); //直接傳遞數組元素,調用時會自動將這些數封裝成數組,並將數組傳遞
pro.param(0, 1, 2, 3); Console.ReadKey();
④與默認參數一樣,可變參數的聲明必須放在方法參數的最后
4)方法的out和ref參數
①out參數側重於輸出,必須在方法內對其賦值
如下圖的聲明編譯器會報錯
正確的使用方法
static void Main(string[] args) { //聲明參數m
int m=0; Program pro = new Program(); //傳遞參數m,必須帶有out參數標識
pro.outPara( out m); Console.WriteLine(m); Console.ReadKey(); } //out參數側重於輸出,必須在方法內對其賦值
public void outPara(out int i) { //方法內部必須對out參數進行賦值
i=5; }
②ref參數側重於修改,但是也可以不修改參數的值
static void Main(string[] args) { //聲明參數m
int m=0; Program pro = new Program(); //傳遞參數m,必須帶有out參數標識
pro.outPara( out m);
//ref參數傳遞之前必須對其賦值,因為在方法內部可能會用到該參數 pro.refPara(ref m); //Console.WriteLine(m);
Console.ReadKey(); } // public void refPara(ref int i) { Console.WriteLine("可以不對參數i進行任何操作!"); }
輸出結果如下:
六,屬性易混淆點辨別
①屬性本身不存值,值是存在這個屬性所封裝的字段里面
class Study { private int nID; //屬性的值存儲在封裝的字段里面
public int NID { get { return nID; } //這里我們給屬性賦值
set { nID = value; } } }
通過訪問屬性字段獲取字段的值
Study stu = new Study(); //通過訪問屬性字段獲取字段的值
int nID = stu.NID;
②屬性的返回值類型和字段的值類型沒有關系
//屬性的值類型為bool
private bool gender; //字段的返回類型為string
public string Gender { get{return gender==true?"男":"女";} set{gender =value=="男"?true:false;} }
屬性的返回值類型決定了get返回值的類型和set參數的類型
//屬性的值類型為bool
private bool gender; //字段的返回類型為string
public string Gender { //get的返回值類型為bool
get{return gender==true?"男":"女";} //set參數類型為bool
set{gender =value=="男"?true:false;} }
③自動屬性到底是怎么回事?
看如下的代碼:
private string strName; //自動屬性封裝strName
public string StrName { get; set; }
這就是所謂的自動屬性封裝字段。在非自動屬性中,程序默認的會有value值來給字段賦值,但是在自動屬性中是怎么賦值的呢?
我們使用.NET Reflector反編譯來看源代碼:
這是我們封轉的屬性代碼:
反編譯set函數源代碼:
我們可以看到.NET會默認為我們的程序生成一個成員變量<StrName>k__BackingField
get函數的源代碼:
返回的也是該成員變量;
那么什么時候可以使用自動屬性呢?
如果對一個字段取值和賦值的時候沒有任何邏輯驗證並且可讀可寫的時候,就可以使用自動屬性。
七,C#類聲明易混淆知識點
①首先給大家說明一個問題就是,文件名和類名必須是一樣的么(就是我們在創建類的時候要命明,這個時候會默認的生成一樣的類名稱)?
如圖所示
這個是必須的么?
我們嘗試修改類名稱為ChildName,然后訪問類
可以看到我們要訪問類,需要通過類名稱訪問而與文件名沒有關系。
②類表達式的執行順序和其意義
Study stu = new Study();
編譯器執行代碼的時候,
首先會先在棧中開辟一塊類型為Study的內存空間放置變量stu
然后在堆中創建該變量的對象
然后調用該對象的構造函數,並且返回該對象在堆中的地址。
好吧,到這里,這次的分享就到此結束了。大家如果閱讀的過程中有什么問題,可以跟我留言交流。