提到類型轉換,首先要明確C#中的數據類型,主要分爲值類型和引用類型:安全
1.經常使用的值類型有:(struct)函數
整型家族:int,byte,char,short,long等等一系列性能
浮點家族:float,double,decimal測試
孤獨的枚舉:enumspa
孤獨的布爾:boolcode
2.經常使用的引用類型有:blog
string,class,array,delegate,interfaceci
值得注意的是,不管是值類型仍是引用類型,在C#中都派生於object,沒錯,這傢伙就是萬惡之源!get
正是由於有了這一特性,因而咱們才能經過裝箱和拆箱愉快地將這些數據類型在值類型,object,引用類型間反覆橫跳。string
固然了,不管是裝箱和拆箱,對於性能都是有消耗的,不到萬不得已的時候儘可能不要用(雖然我才無論這些,只要我用的爽就好了233)
雖然通常不提倡用object類型做爲函數參數,取而代之使用泛型成爲首選,那麼如何判斷泛型參數的具體數據類型並進行有效轉換呢?
好比下面的例子:
1 [System.Serializable] 2 public struct Property<T> where T : struct 3 { 4 public string Label { get; } 5 public T Value { get; } 6 public PropertyType Type { get; } 7 public Property(string label, T value, PropertyType type = PropertyType.Sub) 8 { 9 Label = label; 10 Value = value; 11 Type = type; 12 } 13 14 public static Property<T> operator +(Property<T> a, Property<T> b) 15 { 16 var prop = new Property<T>(); 17 if (a.Label == b.Label && a.Type == b.Type) 18 { 19 //怎麼知道這個值究竟是int仍是float... 20 } 21 return prop; 22 } 23 }
1 public enum PropertyType 2 { 3 Main, 4 Sub 5 }
定義了一個名叫「屬性」的結構體,包含標籤,具體值和屬性類別(是主屬性仍是副屬性),並使用泛型約束數據爲值類型。
如今想要快速對這個結構體進行加法操做,因而增長操做符重載函數,方便愉快的對兩個屬性的值相加,但問題是泛型是沒法強轉爲任何一種非object數據類型,直接相加則更是不可能。
這時就想到了以object類型做爲橋樑,進行具體的類型斷定與轉換:
1 public static Property<T> operator +(Property<T> a, Property<T> b) 2 { 3 if (a.Label == b.Label && a.Type == b.Type) 4 { 5 object tempa = a.Value; 6 object tempb = b.Value; 7 8 object add; 9 if (tempa is int) 10 { 11 add = (int)tempa + (int)tempb; 12 } 13 else if (tempa is float) 14 { 15 add = (float)tempa + (float)tempb; 16 } 17 //...其餘類型 18 else 19 { 20 return new Property<T>(); 21 } 22 23 return new Property<T>(a.Label, (T)add, a.Type); 24 } 25 return new Property<T>(); 26 }
斷定類型時能夠使用is關鍵字,也可直接取得值的類型或泛型類型進行斷定:
1 if (tempa.GetType() == typeof(float)) 2 { 3 4 } 5 //or 6 if (typeof(T) == typeof(float)) 7 { 8 9 }
上面的方案雖然能夠解決類型轉換的需求,但頻繁的拆箱和裝箱以及類型斷定對性能的仍是有必定影響,並且若是每一種類型都寫進if-else,看上去像千層塔通常難受。是時候輪到dynamic登場了。
.Net 4.0 之後開始支持動態數據類型——也就是dynamic關鍵字;使人興奮的是,dynamic能夠被賦值爲任何一種類型的值,固然也包括泛型。
然而值得注意的是,dynamic關鍵字並不會在程序編譯的時候進行校驗,而只在運行時動態斷定,因此使用的時須要格外當心。
固然了,屢次運行時的性能要遠遠高於裝箱和拆箱,並且書寫起來也是至關簡潔美觀(¯﹃¯):
1 public static Property<T> operator +(Property<T> a, Property<T> b) 2 { 3 if (a.Label == b.Label && a.Type == b.Type) 4 { 5 dynamic x1 = a.Value; 6 dynamic x2 = b.Value; 7 return new Property<T>(a.Label, (T)(x1 + x2), a.Type); 8 } 9 return new Property<T>(); 10 }
能夠直接執行相加操做,但若是實際傳入的兩個數據類型並不能相加如bool,則會在運行時報錯;固然了,若是想進一步防止安全,還能夠增長更多的類型斷定語句,如:
1 public static Property<T> operator +(Property<T> a, Property<T> b) 2 { 3 if (a.Label == b.Label && a.Type == b.Type) 4 { 5 if (typeof(T) != typeof(bool) && typeof(T)!=typeof(Enum)) 6 { 7 dynamic x1 = a.Value; 8 dynamic x2 = b.Value; 9 return new Property<T>(a.Label, (T)(x1 + x2), a.Type); 10 } 11 } 12 return new Property<T>(); 13 }
補充一句,dynamic關鍵字在Unity中可能會報錯,由於Unity默認用的是.Net Api爲2.0版本,須要升級爲4.0以後的版本才能使用該關鍵字,具體設置以下:
下面作一個簡單測試:
1 using UnityEngine; 2 3 public class MicrosoftCSharpTest : MonoBehaviour 4 { 5 void Start() 6 { 7 dynamic a = 5.1f; 8 dynamic b = 3; 9 Debug.Log(a + b); 10 11 var hp1 = new Property<int>("Hp", 41); 12 var hp2 = new Property<int>("Hp", 5); 13 var hp = hp1 + hp2; 14 Debug.Log(hp.Label + " : " + hp.Value); 15 16 var miss1 = new Property<float>("MissRate", .1f); 17 var miss2 = new Property<float>("MissRate", .05f); 18 var miss = miss1 + miss2; 19 Debug.Log(miss.Label + " : " + miss.Value); 20 } 21 }