值類型,良構類型,異常處理
值類型
結構
- 值類型:直接包含值,變量引用的位置就是值在內存中實際的存儲位置。
- 引用類型:它的值是對一個的對象實例的應用。
- 聲明結構:struct { }
- 包括屬性、字段、方法、構造器。但是不可以包含用戶定義的默認構造器
裝箱
- 步驟:
- 首先在堆內存上分配好空間。(用於存放值類型的數據以及少許額外開銷)
- 接着發送一次內存複製動作。(當前存儲位置的值類型數據複製到堆上分配好的位置)
- 最後轉化結果是對堆上的新存儲位置的引用。
相反的過程就是拆箱
枚舉
- 枚舉的關鍵特徵是在編譯時聲明瞭一組可以通過名稱來引用的常量值。用其來代替布爾值能改善可讀性。
- 一個默認爲0,後面的根據前一個的值來確定自己的值。
良構類型
重寫object的成員
重寫object的成員
-
重寫ToString():默認情況下對象上調用其會返回類的完全限定名稱。
- 改寫爲返回有用的值
-
重寫GetHashCode()
無論如何重寫Equals()就要重寫GetHashCode()
hash code的作用就是生產與對象值對應的數字,從而高效地平衡散列表有一下幾大原則
- 必須:相等的對象必須有相等的散列碼
- 必須:在特定對象的生存期內,GetHashCode必須總是成功返回一個值,即使對象的數據發送了變化。
- 必須:GetHashCode不應引發任何異常,其總是成功返回一個值
-
重寫Equals():
對象同一性和相同的對象值:兩個同一的引用顯然是相等的,然而,兩個應用不相等的對象也可能是相等的對象。對象標識不同,不一定標識數據不同。
步驟:
- 檢查是否爲null
- 如果是引用類型就檢查引用是否相等
- 檢查數據類型是否相同
- 可能要檢查散列碼是否相等
- 如果基類重寫了Equals()就檢查base.Equals()。
- 比較每一個標識字段,判斷是否相等。
- 重寫GetHashCode()
- 重寫==和!=操作符。
操作符重載
- 實現顯式和隱式轉換操作符並不是對轉型操作符(())進行重載。但是效果一樣。
- 實現轉換操作符時,爲了保證其封裝線,要麼返回值,要麼參數必須是封閉類型。C#不允許在被轉化類型的作用域以外指定轉換。
定義命名空間
- 爲了防止名稱衝突和在引用第三方的程序集時可能造成的大量的衝突。要爲類文件進行一定程度的命名
- 要爲命名空間名稱附加公司名前綴。
- 要爲命名空間名稱中的二級名稱使用穩定的,不隨版本升級而變化的產品名稱。
- 不要定義沒有明確放到一個命名空間中的類型。
- 考慮創建於命名空間層次結構相匹配的文件夾結構
異常處理
異常處理語句
1、throw語句:throw語句用於主動引發一個異常,使用throw語句可以在特定的情形下,自行拋出異常。
throw ExObject; //ExObject是所要拋出的異常對象,該對象是派生自System.Exception類的類對象。
2、try…catch語句
try塊裏的代碼是要來檢測的代碼,有可能引發一個異常。如果真的引發了異常,那麼某個catch塊就要嘗試處理這個異常,可以同時存在多個catch塊,用來捕獲不同的錯誤信息。而finally塊的作用是提供一個最終位置,在其中放入無論是否發生異常都要執行的代碼。finally塊最適合用來執行資源清理。無論try塊中的代碼是否引發一個異常,finally塊都會執行。
try
{
//被監控的代碼
}
catch(異常類名 異常變量)
{
//異常處理
}
3、try…catch…finally
try
{
//被監控的代碼
}
catch(異常類名 異常變量)
{
//異常處理
}
finally
{
//無論監控代碼是否異常都要執行的代碼
}
一個當除以零時拋出異常的實例
using System;
namespace ErrorHandlingApplication
{
class DivNumbers
{
int result;
DivNumbers()
{
result = 0;
}
public void division(int num1, int num2)
{
try
{
result = num1 / num2;
}
catch (DivideByZeroException e)
{
Console.WriteLine("Exception caught: {0}", e);
}
finally
{
Console.WriteLine("Result: {0}", result);
}
}
static void Main(string[] args)
{
DivNumbers d = new DivNumbers();
d.division(25, 0);
Console.ReadKey();
}
}
}
代碼運行的效果
- 另外也可以自己定義自己的異常用戶自定義的異常類是派生自ApplicationException類。下面的實例演示了這點:
using System;
namespace UserDefinedException
{
class TestTemperature
{
static void Main(string[] args)
{
Temperature temp = new Temperature();
try
{
temp.showTemp();
}
catch(TempIsZeroException e)
{
Console.WriteLine("TempIsZeroException: {0}", e.Message);
}
Console.ReadKey();
}
}
}
public class TempIsZeroException: ApplicationException
{
public TempIsZeroException(string message): base(message)
{
}
}
public class Temperature
{
int temperature = 0;
public void showTemp()
{
if(temperature == 0)
{
throw (new TempIsZeroException("Zero Temperature found"));
}
else
{
Console.WriteLine("Temperature: {0}", temperature);
}
}
}
效果:
Exception類和派生類
- System.Exception類是所有異常類的基類,所以可以直接用catch(Exception ex)來捕獲異常信息,但爲了捕獲有關異常的具體信息,我們用更具體的派生類型來處理錯誤。
- C#中如果同時存在多個catch塊,爲了捕獲具體的異常信息,必須從“最具體”到“最不具體”排列。也就是說,用於捕獲Exception的catch語句不能出現在捕獲FormatException的catch語句之前,因爲FormatException比Exception更爲具體。
- 一些常見的預定義的異常類
Exception | 應用程序執行期間發生錯誤 | |
---|---|---|
SystemException | 系統異常 | 所有Exception的基類 |
ArgumentException | 當方法提供的任意一個參數無效時,引發此異常 | |
ArithmeticException | 算數導致的錯誤 | |
DataException | 在使用ADO.NET組件時生成錯誤 | System.Data命名空間提供 |
FormatException | 參數的格式不符合被調用方法的參數規範 | |
IOException | IO錯誤 | System.IO命名空間提供 |
IndexOutOfRangeException | 數組越界 | |
ArgumentNullException | 空引用傳遞給無效參數的方法時引發 | 對應JAVA的空指針 |
DivideByZeroException | 0爲除數 | |
OverflowException | 運算結果過大,無法以目標格式保存 | 比如把一個30位數字賦給int |
ApplicationException | 應用程序執行過程中檢測到由應用程序定義的異常 | |
TargetException | 試圖調用無效目標時 | System.Reflection命名空間提供 |