[C#.NET] 類型轉換前要不要先判斷?直接強制轉型好嗎?

  • 52074
  • 0
  • 2013-07-05

[C#.NET] 類型轉換前要不要先判斷?直接強制轉型好嗎?

先歸納一下在C#裡提供了哪些型別的轉換,轉型和型別轉換 (C# 程式設計手冊)

boxing/unboxing:

Boxing 是一種隱含轉換,可將實值型別轉換成 object 型別,Unboxing 是明確轉型將object轉換成其它型別,我們應該極力的避免這樣的狀況發生。

int a = 5;
object b = (object)a;//boxing

object c = 5;
int d = (int)c;//unboxing 

 

 

 

字串型別轉換成實值型別:

int f = int.Parse("3");

明確轉型:

long e = System.Convert.ToInt64(257);
bool g = System.Convert.ToBoolean("true");

byte h = (byte)e; //long轉byte可能會造成資料丟失 

 

 

參考型別的轉換:

比如我有兩個類別叫Company 及Family

public class Company 
{
    public string Name { get; set; }
    public string Address { get; set; }
}

public class Family 
{
    public string Name { get; set; }
    public string Address { get; set; }
}

 

 

我想要用 as 將 company 轉成 Family,沒意外的話 family 會得到null

object company = new Company();
Family family = company as Family;

 

 

 

如果使用明確轉型,沒意外應該會拋出InvalidCastException的例外。

object company = new Company();
Family family = (Family)company;

 

 

 

記得以前剛接觸C#時,需要一個功能叫"驗証字串是否為數字",下列的寫法也很常見(相當的不建議這樣寫),別忘了!使用try/catch會降低程式碼的效能,我們應該找尋其他的辦法。

public bool IsNumeric(string data)
{
    try
    {
        long h = System.Convert.ToInt64("20");
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}

 

 

使用明確轉型又有可能會丟包或出錯(InvalidCastException),我們能有其他辦法嗎?有的,我們可以先判斷資料型別然後再轉型。


實值型別的轉換判斷,使用TryParse方法,轉換結果會丟到result,並回傳bool是否為數字

public bool IsNumeric(string data)
{
    int result;
    if (int.TryParse(data, out result))
        return true;
    else
        return false;
}

 

 

當然也可以寫成這樣,不必擔心數據是否丟包,轉換失敗會回傳null,轉換成功會得到正確的byte資料。

public static byte? IsNumeric(string data)
{
    byte result;
    if (byte.TryParse(data, out result))
        return (byte)result;
    else
        return null;
}

 

 

用is關鍵字,無法轉換會回傳null,轉換成功會得到正確的int資料。

public int? IsNumeric(object o)
{
    int i;
    if (o is byte)
    {
        i = (int)o;
        return i;
    }
    else
    {
        return null;
    }
}

 

 


參考型別的轉換判斷,使用is關鍵字判斷型別再用as轉型,下列程式碼是我常用在搜尋控制項的片斷。

foreach (Control ctrl in this.Controls)
{
    if (ctrl is TextBox)
    {
        TextBox textbox = ctrl as TextBox;
        Console.WriteLine(textbox.Text);
    }
    else if (ctrl is Button)
    {
        Button button = ctrl as Button;
        Console.WriteLine(button.Text);
    }
}

 

 

或是寫成這樣

foreach (Control ctrl in this.Controls)
{
    if (ctrl is TextBox)
    {
        TextBox textbox = (TextBox)ctrl;
        Console.WriteLine(textbox.Text);
    }
    else if (ctrl is Button)
    {
        Button button = (Button)ctrl;
        Console.WriteLine(button.Text);
    }
}

 

 

我會比較建議使用as來轉型,用as轉型時若轉型失敗會得到null不會發生例外,以下面的片斷程式碼來看,甚至不需要用到is,直接判斷as轉型是否為null

object company = new Company();
Family family = company as Family;

if (family != null)
{
    //TODO
}
else
{
    //TODO
}

 

 

若是用明確轉型,我們可能還要檢查是否為null以及捕捉例外,這樣一來便會降低程式碼的效能

object company = new Company();
Family family = null;
try
{
    family = (Family)company;
}
catch (InvalidCastException ex)
{
    //throw ex;
}

 

 


後記:

1.應該優先選擇使用as來轉型,當無法使用as轉型時,可以先使用is判斷,再進行明確轉型。

2.當可以使用as轉型時,判斷轉型結果是否為null,便可省略is判斷。

3.必要時is加上as可以讓程式碼更靈活。

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo