//控制檯輸入整數和字符串 int age = int.Parse(Console.ReadLine()); string name = Console.ReadLine(); //控制檯輸入浮點數 double salary = double.Parse(Console.ReadLine()); double addSalary = Convert.ToDouble(Console.ReadLine()); //控制檯格式化輸出 Console.WriteLine("這是第一個C#控制檯程序"); Console.WriteLine("Your name is {0}, age is {1}, and salary is {2:f2}, addSalary is {3}", name, age, salary, addSalary.ToString()); //格式化到字符串 int age = 32; double salary = 12000.59; String name = "zhangsan"; String outstr = String.Format("name={0}, age={1}, salary={2:f1}", name, age, salary); Console.WriteLine(outstr); //輸出日期和時間,DateTime.Today只獲取日期 Console.WriteLine("{0:D} {0:t}", DateTime.Now); DateTime dt = new DateTime(2017, 4, 1, 13, 16, 32, 108); dt.ToString("y yy yyy yyyy");//17 17 2017 2017 dt.ToString("M MM MMM MMMM");//4 04 四月 四月 dt.ToString("d dd ddd dddd");//1 01 週六 星期六 dt.ToString("t tt");//下 下午 dt.ToString("H HH");//13 13 dt.ToString("h hh");//1 01 dt.ToString("m mm");//16 16 dt.ToString("s ss");//32 32
C#中的數據類型包含值類型(int,double,float,string等),引用類型(object,dynamic和string三種內置的引用類型,以及class等)和指針類型(C#中不建議使用指針類型)。數組
**如何區別值類型和引用類型? **
值類型:能夠直接賦值的一般是值類型,好比int,float等,String類型除外,它是特殊的引用類型;
引用類型:一般是對象,好比從Object派生的對象,能夠設置爲null,還須要使用new操做符來申請內存空間構造對象;好比本身實現的class,系統定義的class等數據結構
類型檢查
sizeof()判斷類型的大小,判斷值類型有效,因爲在C#中引用類型相似C++中的引用,不存儲內存空間,所以不能用sizeof()計算引用類型的空間大小;
typeof()返回數據的類型app
內置的引用類型函數
//對象(Object)類型,裝箱就是這裏將值類型轉換爲引用類型,反之就是拆箱 object obj1 = 100; object obj2 = 100.5; Console.WriteLine("obj1 is {0}, obj2 is {1}", obj1.GetType().ToString(), obj2.GetType().ToString()); //動態(Dynamic)類型,能夠是值類型,也能夠是引用自定義class類型 dynamic obj3 = 100; dynamic obj4 = 100.5; Console.WriteLine("obj3 is {0}, obj4 is {1}", obj3.GetType().ToString(), obj4.GetType().ToString()); //字符串類型,使用@將轉義字符(\)看成普通字符對待 string str1 = @"C:\Windows"; string str2 = "C:\\Windows"; if (str1 == str2) { Console.WriteLine("他們相等"); }
動態類型與對象類型類似,可是對象類型變量的類型檢查是在編譯時發生的,而動態類型變量的類型檢查是在運行時發生的。指針
用戶自定義引用類型
用戶或系統實現的class、interface 或 delegate等;日誌
顯示和隱式轉換
等同於C++的操做code
int v = 10; double d = v; //隱式轉換 int v2 = (int)d; //顯式轉換
AS操做(引用類型轉換)orm
//子類到基類的轉換,兩種方法均可以 //第一種是強制轉換,在編譯期間會進行判斷 //第二種轉換在失敗時base b會爲空,不拋出異常 base b = subclass; base b = subclass as base; //基類到派生類的轉換: //C++:subclass* sub = dynamic_cast<base>(base); //if (sub != nullptr) 須要作一下判斷是否轉換成功 Rectangle rect2 = sh as Rectangle; if (rect2 != null) { //須要作一下判斷,轉換失敗rect2爲空,但不會拋出異常 }
使用AS操做符轉換,可是AS只能用於引用類型和可爲空的類型。使用as有不少好處,當沒法進行類型轉換時,會將對象賦值爲NULL,避免類型轉換時報錯或是出異常。C#拋出異常在進行捕獲異常並進行處理是很消耗資源的,若是隻是將對象賦值爲NULL的話是幾乎不消耗資源的(消耗很小的資源)。對象
裝箱和拆箱(值類型和引用類型轉換)繼承
object obj1 = 100; object obj2 = 100.5; Console.WriteLine("obj1 is {0}, obj2 is {1}", obj1.GetType().ToString(), obj2.GetType().ToString());
裝箱和拆箱在值類型和引用類型之間架起了一座橋樑,使得任何 value-type 的值均可以轉換爲 object 類型的值,反過來轉換也能夠。 裝箱:裝箱是指將一個值類型的數據隱式地轉換成一個對象類型(object)的數據。執行裝箱操做時不可避免的要在堆上申請內存空間,並將堆棧上的值類型數據複製到申請的堆內存空間上,這確定是要消耗內存和cpu資源的。注意:在執行裝箱轉換時,也可使用顯式轉換。 拆箱:拆箱是指將一個對象類型的數據顯式地轉換成一個值類型數據。拆箱過程是裝箱的逆過程,是將存儲在堆上的引用類型值轉換爲值類型並賦給值類型變量。拆箱操做分爲兩步:一是檢查對象實例,確保它是給定值類型的一個裝箱值;而是將該值從實例複製到值類型變量中。裝箱和拆箱都是要消耗內存和cpu資源的,也就形成效率下降,因此要儘可能避免使用。
//num1不能爲空值,可是可使用?符號來定義可空值類型 double? num1 = null; double? num2 = 3.14157; double num3; // num1 若是爲空值則返回 5.34 num3 = num1 ?? 5.34; Console.WriteLine("num3 的值: {0}", num3); num3 = num2 ?? 5.34; Console.WriteLine("num3 的值: {0}", num3); Console.ReadLine();
//聲明數組 int[] age; double[] balance; //初始化數組並賦值 age = new int[5] { 1, 2, 3, 4, 5 }; //也能夠不指定長度:age = new int[] { 1, 2, 3, 4, 5 }; //初始化數組使用默認值0 balance = new double[10]; //訪問數組元素 int val = age[3]; //遍歷數組元素 foreach (int v in age) { Console.WriteLine("{0}", v); }
//聲明數組 int[,] age; double[,] balance; //初始化數組並賦值 age = new int[2,3] { { 1, 2, 3 }, { 4, 5, 6 } }; //也能夠不指定長度:age = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } }; //初始化數組使用默認值0 balance = new double[5, 10]; //訪問數組元素 int val = age[0,1]; //遍歷數組元素 foreach (int v in age) { Console.WriteLine("{0}", v); }
交錯數組是數組的數組,不一樣於多維數組。多維數組本質上元素都是一個數據類型,而交錯數組的元素本質上是另一個數組。交錯數組和C++的多維數組很相似,聲明和使用看起來都同樣,要特別注意!
//聲明數組 int[][] scores; //初始化數組 scores = new int[5][]; for (int i = 0; i < scores.Length; i++) { //數組元素是一個有4個元素的數組 scores[i] = new int[4] { i * i + 1, i * i + 2, i * i + 3, i * i + 4 }; } //也能夠直接初始化:scores = new int[2][] { new int[] { 92, 93, 94 }, new int[] { 85, 66, 87, 88 } }; //訪問數組元素 int val = scores[0][2]; //遍歷數組元素 for (int i = 0; i < 5; i++) { for (int j = 0; j < 4; j++) { Console.WriteLine("a[{0}][{1}] = {2}", i, j, scores[i][j]); } }
Array 類是 C# 中全部數組的基類,它是在 System 命名空間中定義。
Array 類提供了各類用於數組的屬性和方法。
Array類是一個抽象類,不能被實例化。
struct Books { public string title; public string author; }; Books b; b.title = "Eleven"; b.author = "ZhangSan"; Console.WriteLine("{0}, {1}", b.title, b.author);
在 C# 中,結構體是值類型數據結構。它使得一個單一變量能夠存儲各類數據類型的相關數據。
C# 中的結構有如下特色:
類和結構有如下幾個基本的不一樣點:
C# 枚舉是值類型。換句話說,枚舉包含本身的值,且不能繼承或傳遞繼承。
//默認從0開始,依次加1 enum Days { Sun, Mon, tue, Wed, thu, Fri, Sat }; //指定從10開始,中間Fri指定爲20,Sat就是21 enum Days2 { Sun = 10, Mon, tue, Wed, thu, Fri=20, Sat }; //和C++不同,這裏會打印字符串Sun,Fri,Sat Console.WriteLine("{0}, {1}, {2}", Days.Sun, Days.Fri, Days.Sat); Console.WriteLine("{0}, {1}, {2}", Days2.Sun, Days2.Fri, Days2.Sat); //強制將枚舉轉換爲int,纔會獲得和C++同樣的結果 Console.WriteLine("{0}, {1}, {2}", (int)Days.Sun, (int)Days.Fri, (int)Days.Sat); Console.WriteLine("{0}, {1}, {2}", (int)Days2.Sun, (int)Days2.Fri, (int)Days2.Sat);
和C++同樣,C#也有值傳遞和引用傳遞,可是比C++多一個參數傳出功能。
//引用傳遞使用ref而不是& public void swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } //輸出參數傳遞,對於未初始化的參數獲取頗有用 public void GetValues(out int a, out int b) { Console.WriteLine("請輸入第一個值: "); a = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("請輸入第二個值: "); b = Convert.ToInt32(Console.ReadLine()); } int x = 100; int y = 200; MyClass n = new MyClass(); n.swap(ref x, ref y); Console.WriteLine("在交換以後,x 的值: {0}", x); Console.WriteLine("在交換以後,y 的值: {0}", y); int a; int b; n.GetValues(out a, out b); Console.WriteLine("a={0}, b={1}", a, b); //這裏不能使用swap,由於a,b都沒有初始化 //n.swap(ref a, ref b);
C#的引用傳遞可使用值傳遞也能夠顯式使用引用傳遞,效果是同樣的。
C#將Object obj2 = obj1當成對象引用,而不是建立新的對象,建立新對象都使用new操做符。而C++對象引用必須強制使用&符號,好比:Object& obj2 = obj1。這點和C++有很大區別!
class MyData { public int val = 0; double v2 = 100.3232; //經過傳遞引用改變數據 static public void ChangeValue1(ref MyData d) { d.val = 60; } //經過傳遞值改變數據,由於這個值是一個引用類型,所以能夠改變數據 //若是參數是值類型,如int,float等就不能夠 static public void ChangeValue2(MyData d) { d.val = 100; } } //使用new建立對象 MyData v = new MyData(); MyData.ChangeValue1(ref v); Console.WriteLine("v.val={0}", v.val); MyData.ChangeValue2(v); Console.WriteLine("new v.val={0}", v.val);
C#數組也是對象,所以參數傳遞中的數組等同於引用傳遞:
//也能夠static void init(ref int[] array)這樣聲明 static void init(int[] array) { int index = 0; int size = array.Length; for (int i=0; i<size; i++) { array[i] = ++index; } } //建立一個10個元素長度的數組 int[] array = new int[10]; //使用參數傳遞初始化數組,等同於Program.init(ref array); Program.init(array); //打印數組元素 foreach (int i in array) { Console.Write("{0} ", i); }
相似於C/C++的可變參數(不定長參數),C# 經過使用參數數組來實現不可知個數的參數傳遞。
1.帶 params 關鍵字的參數類型必須是一維數組,不能使用在多維數組上;
2.不容許和 ref、out 同時使用;
3.帶 params 關鍵字的參數必須是最後一個參數,而且在方法聲明中只容許一個 params 關鍵字。
4.不能僅使用 params 來使用重載方法。
5.沒有 params 關鍵字的方法的優先級高於帶有params關鍵字的方法的優先級
//參數數組只能傳遞int類型 public static void UseParams(params int[] list) { for (int i = 0; i < list.Length; i++) { Console.Write(list[i] + " "); } Console.WriteLine(); } //能夠傳遞任意object類型 public static void UseParams2(params object[] list) { for (int i = 0; i < list.Length; i++) { Console.Write(list[i] + " "); } Console.WriteLine(); } UseParams(1, 2, 3, 4); UseParams2(1, 'a', "Apple"); UseParams2(); //不填入參數 //和UseParams(1, 2, 3, 4);等價 int[] myIntArray = { 5, 6, 7, 8, 9, }; UseParams(myIntArray); object[] myObjArray = { 1, 'b', "boom", "app" }; UseParams2(myObjArray); //輸出爲"System.Int32[]",這裏把數組看做爲一個object類型了 UseParams2(myIntArray);
靜態常量
所謂靜態常量就是在編譯期間會對變量進行解析,再將常量的值替換成初始化的值。
動態常量
所謂動態常量就是編譯期間會將變量標記只讀常量,而不用常量的值代替,這樣在聲明時能夠不初始化,能夠延遲到構造函數初始化。
const修飾的常量是上述中的第一種,即靜態常量,而readonly是上述中第二種即動態常量。他們的區別能夠從靜態常量和動態常量的特性來講明:
和C++同樣,C#也能夠定義一系列預處理指令。能夠在項目屬性中設置預處理指令:
勾選DEBUG和TRACE常量會定義這兩個預約義指令,在條件編譯符號中還能夠自行定義須要的預處理指令,用空格分開。
另外還能夠在代碼文件的using指令前定義預處理指令:
#define GPU using System; ... #if GPU Console.WriteLine("Use GPU"); #else #warning Only Support GPU ! #endif
這裏使用#warning在編譯時產生一個編譯警告(還能夠#error產生編譯錯誤)。
另外比較經常使用的就是代碼段管理預處理指令,在IDE中能夠摺疊被#region包圍的代碼:
#region 私有成員 private int _width = 0; private int _height = 0; #endregion #region 公有方法 public void Submit() { } public static void Add(MyClass A, MyClass B) { } #endregion
這樣一來就能夠摺疊這段代碼,若是沒有顯示+號,就須要在菜單->編輯->大綱顯示,開啓代碼的大綱顯示功能。
C#提供了很豐富的異常處理機制,這點和C++很類似,連關鍵字try,catch,finally都是如出一轍。整體上分爲兩類異常:SystemException和ApplicationException。
下面的代碼展現自定義異常類的最多見用法:
public class MyClass { public int Work(int a, int b) { if (b == 0) { throw new MyException("除數不能爲零!"); } return a / b; } } //自定義異常處理類,從ApplicationException派生 public class MyException : ApplicationException { public MyException(string messag) : base(messag) { } } try { MyClass my = new MyClass(); int value = my.Work(100, 0); Console.WriteLine("value is {0}", value); } catch (MyException e) { //捕獲自定義異常 Console.WriteLine("MyException : {0}", e.Message); } catch (Exception e) { Console.WriteLine("Exception : {0}", e.Message); //若是不想處理,仍然能夠繼續拋出異常 throw e; } finally { //不管是否拋出異常都會執行這段代碼 Console.WriteLine("程序退出"); }
一、通用文件流FileStream操做,便可寫文件也可讀取文件
//打開文件流 FileStream F = new FileStream("test.dat", FileMode.OpenOrCreate, FileAccess.ReadWrite); //寫文件數據 for (int i = 1; i <= 20; i++) { F.WriteByte((byte)i); } //讀取文件流 F.Position = 0; for (int i = 0; i <= 20; i++) { Console.Write(F.ReadByte() + " "); } //關閉文件 F.Close();
二、簡單文本文件的寫入StreamWriter和讀取StreamReader
//寫文本文件 string[] names = new string[] { "Zara Ali", "Nuha Ali" }; //使用using也能夠關閉文件 using (StreamWriter sw = new StreamWriter("names.txt")) { foreach (string s in names) { sw.WriteLine(s); } } //讀取文本文件 string line = ""; using (StreamReader sr = new StreamReader("names.txt")) { while ((line = sr.ReadLine()) != null) { Console.WriteLine(line); } }
三、二進制文件的讀BinaryReader和寫BinaryWriter
try { //從控制檯輸入數據並寫入二進制文件 BinaryWriter bw = new BinaryWriter(new FileStream("mydata", FileMode.Create)); Int32 vInt = Convert.ToInt32(Console.ReadLine()); Double vDoub = Convert.ToDouble(Console.ReadLine()); String vStr = Console.ReadLine(); bw.Write(vInt); bw.Write(vDoub); bw.Write(vStr); bw.Close(); } catch (IOException e) { Console.WriteLine(e.Message); return; } catch (Exception e) { Console.WriteLine(e.Message); return; } try { // 讀取二進制文件 BinaryReader br = new BinaryReader(new FileStream("mydata", FileMode.Open)); Console.WriteLine("Read:\n{0}\n{1}\n{2}", br.ReadInt32(), br.ReadDouble(), br.ReadString()); br.Close(); } catch (IOException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine(e.Message); }
DirectoryInfo 類
DirectoryInfo 類派生自 FileSystemInfo 類。它提供了各類用於建立、移動、瀏覽目錄和子目錄的方法。該類不能被繼承。
**FileInfo 類 **
FileInfo 類派生自 FileSystemInfo 類。它提供了用於建立、複製、刪除、移動、打開文件的屬性和方法,且有助於 FileStream 對象的建立。該類不能被繼承。
下面是一個自動刪除過時日誌的函數,使用了遞歸遍歷所有文件:
void DeleteLog(string folderFullName, int preDays = 14) { DateTime timeUp = DateTime.UtcNow.AddDays(-preDays); Console.WriteLine("Will delete old log befor {0}===>", timeUp.ToString()); DirectoryInfo TheFolder = new DirectoryInfo(folderFullName); foreach (DirectoryInfo NextFolder in TheFolder.GetDirectories()) { //遍歷子文件夾 DeleteLog(NextFolder.FullName); } foreach (FileInfo fileName in TheFolder.GetFiles()) { //刪除指定時間以前的文件 if (DateTime.Compare(timeUp, fileName.LastWriteTime) >= 0) { Console.WriteLine(fileName.FullName); File.Delete(fileName.FullName); } } }