1. 程式人生 > 程式設計 >詳解C# 泛型中的資料型別判定與轉換

詳解C# 泛型中的資料型別判定與轉換

提到型別轉換,首先要明確C#中的資料型別,主要分為值型別和引用型別:

1.常用的值型別有:(struct)

整型家族:int,byte,char,short,long等等一系列

浮點家族:float,double,decimal

孤獨的列舉:enum

孤獨的布林:bool

2.常用的引用型別有:

string,class,array,delegate,interface

值得注意的是,無論是值型別還是引用型別,在C#中都派生於object,沒錯,這傢伙就是萬惡之源!

正是因為有了這一特性,於是我們才能通過裝箱和拆箱愉快地將這些資料型別在值型別,object,引用型別間反覆橫跳。

當然了,無論是裝箱和拆箱,對於效能都是有消耗的,不到萬不得已的時候儘量不要用(雖然我才不管這些,只要我用的爽就行了233)

雖然一般不提倡用object型別作為函式引數,取而代之使用泛型成為首選,那麼如何判斷泛型引數的具體資料型別並進行有效轉換呢?

比如下面的例子:

[System.Serializable]
public struct Property<T> where T : struct
{
  public string Label { get; }
  public T Value { get; }
  public PropertyType Type { get; }
  public Property(string label,T value,PropertyType type = PropertyType.Sub)
  {
    Label = label;
    Value = value;
    Type = type;
  }

  public static Property<T> operator +(Property<T> a,Property<T> b)
  {
    var prop = new Property<T>();
    if (a.Label == b.Label && a.Type == b.Type)
    {
      //怎麼知道這個值到底是int還是float...
    }
    return prop;
  }
}
 public enum PropertyType
 {
   Main,Sub
 }

定義了一個名叫「屬性」的結構體,包含標籤,具體值和屬性類別(是主屬性還是副屬性),並使用泛型約束資料為值型別。

現在想要快速對這個結構體進行加法操作,於是增加操作符過載函式,方便愉快的對兩個屬性的值相加,但問題是泛型是無法強轉為任何一種非object資料型別,直接相加則更是不可能。

這時就想到了以object型別作為橋樑,進行具體的型別判定與轉換:

public static Property<T> operator +(Property<T> a,Property<T> b)
  {
    if (a.Label == b.Label && a.Type == b.Type)
    {
      object tempa = a.Value;
      object tempb = b.Value;

      object add;
      if (tempa is int)
      {
        add = (int)tempa + (int)tempb;
      }
      else if (tempa is float)
      {
        add = (float)tempa + (float)tempb;
      }
      //...其他型別
      else
      {
        return new Property<T>();
      }

      return new Property<T>(a.Label,(T)add,a.Type);
    }
    return new Property<T>();
  }

判定型別時可以使用is關鍵字,也可直接取得值的型別或泛型型別進行判定:

if (tempa.GetType() == typeof(float))
      {

      }
      //or
      if (typeof(T) == typeof(float))
      {

      }

上面的方案雖然可以解決型別轉換的需求,但頻繁的拆箱和裝箱以及型別判定對效能的還是有一定影響,而且如果每一種型別都寫進if-else,看上去像千層塔一般難受。是時候輪到dynamic登場了。

.Net 4.0 以後開始支援動態資料型別——也就是dynamic關鍵字;令人興奮的是,dynamic可以被賦值為任何一種型別的值,當然也包括泛型。

然而值得注意的是,dynamic關鍵字並不會在程式編譯的時候進行校驗,而只在執行時動態判定,所以使用的時需要格外小心。

當然了,多次執行時的效能要遠遠高於裝箱和拆箱,而且書寫起來也是相當簡潔美觀(¯﹃¯):

public static Property<T> operator +(Property<T> a,Property<T> b)
  {
    if (a.Label == b.Label && a.Type == b.Type)
    {
      dynamic x1 = a.Value;
      dynamic x2 = b.Value;
      return new Property<T>(a.Label,(T)(x1 + x2),a.Type);
    }
    return new Property<T>();
  }

可以直接執行相加操作,但如果實際傳入的兩個資料型別並不能相加如bool,則會在執行時報錯;當然了,如果想進一步防止安全,還可以增加更多的型別判定語句,如:

public static Property<T> operator +(Property<T> a,Property<T> b)
  {
    if (a.Label == b.Label && a.Type == b.Type)
    {
      if (typeof(T) != typeof(bool) && typeof(T)!=typeof(Enum))
      {
        dynamic x1 = a.Value;
        dynamic x2 = b.Value;
        return new Property<T>(a.Label,a.Type);
      }
    }
    return new Property<T>();
  }

補充一句,dynamic關鍵字在Unity中可能會報錯,因為Unity預設用的是.Net Api為2.0版本,需要升級為4.0之後的版本才能使用該關鍵字,具體設定如下:

詳解C# 泛型中的資料型別判定與轉換

下面做一個簡單測試:

using UnityEngine;

public class MicrosoftCSharpTest : MonoBehaviour
{
  void Start()
  {
    dynamic a = 5.1f;
    dynamic b = 3;
    Debug.Log(a + b);

    var hp1 = new Property<int>("Hp",41);
    var hp2 = new Property<int>("Hp",5);
    var hp = hp1 + hp2;
    Debug.Log(hp.Label + " : " + hp.Value);

    var miss1 = new Property<float>("MissRate",.1f);
    var miss2 = new Property<float>("MissRate",.05f);
    var miss = miss1 + miss2;
    Debug.Log(miss.Label + " : " + miss.Value);
  }
}

詳解C# 泛型中的資料型別判定與轉換

以上就是詳解C# 泛型中的資料型別判定與轉換的詳細內容,更多關於C# 泛型 資料型別判定與轉換的資料請關注我們其它相關文章!