1. 程式人生 > 實用技巧 >c# 個人筆記

c# 個人筆記



基礎

靜態--static

抽象--abstract

值型別

型別 描述 範圍 預設值
bool 布林值 True 或 False False
byte 8 位無符號整數 0 到 255 0
char 16 位 Unicode 字元 U +0000 到 U +ffff '\0'
decimal 128 位精確的十進位制值,28-29 有效位數 (-7.9 x 1028 到 7.9 x 1028) / 100 到 28 0.0M
double 64 位雙精度浮點型 (+/-)5.0 x 10-324 到 (+/-)1.7 x 10308 0.0D
float 32 位單精度浮點型 -3.4 x 1038 到 + 3.4 x 1038 0.0F
int 32 位有符號整數型別 -2,147,483,648 到 2,147,483,647 0
long 64 位有符號整數型別 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 0L
sbyte 8 位有符號整數型別 -128 到 127 0
short 16 位有符號整數型別 -32,768 到 32,767 0
uint 32 位無符號整數型別 0 到 4,294,967,295 0
ulong 64 位無符號整數型別 0 到 18,446,744,073,709,551,615 0
ushort 16 位無符號整數型別 0 到 65,535 0

值傳遞

引用傳遞--ref

介面

什麼是介面?

  • 介面就是一種規範,協議(*),約定好遵循某種規範就可以寫通用的程式碼。
  • 定義了一組具有各種功能的方法。(只是一種能力,沒有具體實現,像抽象方法一樣,“光說不做”)。

介面存在的意義

  • 多型,程式可拓展性,讓程式變得更靈活,節省成本,提高效率。
  • 介面解決了類的多繼承的問題。
  • 介面解決了類的繼承以後體積龐大的問題。
  • 介面之間可以實現多繼承。

總結

  • 子類繼承抽象類,實現介面(介面中定義的方法)。
  • 介面中的成員必須不能有實現,介面不能例項化。
  • 介面中的成員不能有訪問修飾符(public、private等),預設是public。
  • 介面中可以有屬性、方法、索引器等(其實這些都是方法),但不能有欄位。
  • 就扣中的所有成員必須被子類中全部實現,除非子類是抽象類,把就扣中的成員標記為抽象的。
  • 當一個類同時繼承父類,並且實現多個介面的時候,必須將繼承類寫在第一個,然後再用逗號隔開再寫介面
  • 顯示實現介面沒有訪問修飾符,預設是私有的。
  • 顯示實現介面時,在方法名稱前加了介面名,如:介面名.方法

異常處理

什麼是異常?

程式執行時發生的錯誤。(錯誤並不一定是程式設計師的原因,例如:伺服器關閉或者資料庫關閉,導致程式無法獲取資料等;操作的對應檔案沒了,或者檔案許可權被修改導致許可權不足等;程式內計算數值時被除數為0;使用物件時物件重新賦值為null;)

當程式發生異常後不進行處理會導致整個程式直接崩潰。

處理異常的一般程式碼模式

using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //可能發生異常的程式碼,當遇到異常時後續程式碼不執行
            }
            catch
            {
                //處理異常的程式碼,記錄日誌(log4net),繼續向上丟擲等操作
                //只有發生了異常才會執行此處程式
            }
            finally
            {
                //此處程式碼無論是否發生異常都會執行
                //程式碼清理,資源釋放等
            }
        }
    }
}

案例

using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p = null;
            p.Name = "張三";
            Console.WriteLine(p.Name);
            Console.ReadKey();
        }       
    }
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}
執行結果

catch的多種寫法

寫法一
using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int n = 20, m = 0;
                int sum = n / m;
                Console.WriteLine(sum);
            }
            //可以獲取try內的所有異常,但是無法獲取具體異常
            catch
            {
                Console.WriteLine("發生了異常!");
            }
        }
    }
  
}
寫法二
using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int n = 20, m = 0;
                int sum = n / m;
                Console.WriteLine(sum);
            }
            //可以獲取所有異常,並且可以獲取指定的異常資訊
            catch(Exception e)
            {
                Console.WriteLine("發生異常");
                Console.WriteLine(e.Message);       //異常資訊
                Console.WriteLine(e.Source);        //發生異常的具體物件
                Console.WriteLine(e.StackTrace);    //發生異常的堆疊
            }
        }
    }
  
}
方法三
using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int n = 20, m = 0;
                int sum = n / m;
                Console.WriteLine(sum);
            }
            //對不同的異常採用不同的方式處理(使用多個catch捕獲異常)
            catch(NullReferenceException e)
            {
                Console.WriteLine("空指標異常:{0}",e.Message);
            }
            catch(DivideByZeroException e)
            {
                Console.WriteLine("除數為0,詳細資訊:{0}",e.StackTrace);
            }
            catch(ArgumentException e)
            {
                Console.WriteLine("引數異常,詳細資訊:{0}",e.StackTrace);
            }
            catch(Exception e)
            {
                //捕獲所有異常,放在其他捕獲異常後面
                Console.WriteLine(e.StackTrace);
            }
            Console.ReadKey();
        }
    }
  
}

finally

catch有無法捕獲到的異常時,程式崩潰,但在程式崩潰前會執行finally中的程式碼,而finally塊後的程式碼則由於程式崩潰後無法執行。

如果在catch塊中又引發了異常,則finally塊中的內碼表會在繼續引發異常之前執行,但是在finally後面的程式碼則不會執行。

當catch塊中有return語句時,finally中的程式碼會在return之前執行,但是finally塊之後的程式碼不會執行。

throw

throw new Exception
using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                try
                {
                    Console.WriteLine("請輸入一個名字:");
                    string name = Console.ReadLine();
                    if (name == "張三")
                    {
                        //手動寫異常資訊(不推薦使用)
                        throw new Exception("名字錯誤!");
                    }
                    else
                    {
                        Console.WriteLine("名字正確:{0}", name);
                    }

                }
                catch (Exception e)
                {
                    Console.WriteLine("發生異常!");
                    Console.WriteLine(e.Message);
                    Console.WriteLine(e.StackTrace);
                }
            }
        }
    }
}
throw
using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            M1();
        }
        static void M1()
        {
            try
            {
                int n = 20, m = 0;
                int sum = n / m;
                Console.WriteLine("結果:{0}",sum);
            }
            catch (Exception)
            {
                Console.WriteLine("捕獲了異常並進行了處理!");
                throw;
            }
        }
    }
  
}

throw表示如果還有異常則向上丟擲,如果不寫的話在其他地方呼叫M1這個方法
的時候又引發了其他異常則無法捕獲

throw單獨寫時只能在catch塊中寫

字串操作

判斷是否為同一個物件?

判斷物件的三種方法(==,等於,ReferenceEquals)

using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.Name = "張三";
            p1.Age = 18;
            p1.Email = "[email protected]";

            Person p2 = new Person();
            p2.Name = "張三";
            p2.Age = 18;
            p2.Email = "[email protected]";
            p2 = p1;

            Console.WriteLine(p1 == p2);
            Console.WriteLine(p1.Equals(p2));
            Console.WriteLine(object.ReferenceEquals(p1,p2));
            Console.ReadKey();
        }

    }

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
    }
}

上面輸出的結果都為True

using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string str1 = new string(new char[] { 'a', 'b', 'c' });
            string str2 = new string(new char[] { 'a', 'b', 'c' });
			
            Console.WriteLine(str1);//abc
            Console.WriteLine(str2);//abc
            
            Console.WriteLine(str1==str2);//true	
            Console.WriteLine(str1.Equals(str2));//true
            Console.WriteLine(object.ReferenceEquals(str1,str2));//false
            Console.ReadKey();
        }

    }
}

上面這段程式碼的輸出結果和之前的不一樣了,有兩種輸出結果。是什麼原因導致了兩種不同的結果呢?

Equals
  public static bool Equals(string a, string b)
  {
      if (a == b)
      {
          return true;
      }
      if ((a == null) || (b == null))
      {
          return false;
      }
      if (a.Length != b.Length)
      {
          return false;
      }
      return EqualsHelper(a, b);
  }
==
public static bool operator ==(string a, string b) =>
    Equals(a, b);

ReferenceEquals
public static bool ReferenceEquals(object objA, object objB) => 
    ((bool) (objA == objB));

通過反編譯之後發現,Equals與==都是對比字串,當字串的內容一樣,長度一樣,那麼對比結果就是True。然而ReferenceEquals則是對比object型別的資料,是對比的物件,需要生成的物件一致才行,在上面演示程式碼處,使用了new來生成兩個新的物件,那麼這兩個就不是同一個物件了,所以返回false。

在地址堆疊中,只是宣告兩個變數(如string str = "hello";string str1 = "hello"