詳解C# 泛型中的數(shù)據(jù)類型判定與轉(zhuǎn)換
提到類型轉(zhuǎn)換,首先要明確C#中的數(shù)據(jù)類型,主要分為值類型和引用類型:
1.常用的值類型有:(struct)
整型家族:int,byte,char,short,long等等一系列
浮點家族:float,double,decimal
孤獨的枚舉:enum
孤獨的布爾:bool
2.常用的引用類型有:
string,class,array,delegate,interface
值得注意的是,無論是值類型還是引用類型,在C#中都派生于object,沒錯,這家伙就是萬惡之源!
正是因為有了這一特性,于是我們才能通過裝箱和拆箱愉快地將這些數(shù)據(jù)類型在值類型,object,引用類型間反復橫跳。
當然了,無論是裝箱和拆箱,對于性能都是有消耗的,不到萬不得已的時候盡量不要用(雖然我才不管這些,只要我用的爽就行了233)
雖然一般不提倡用object類型作為函數(shù)參數(shù),取而代之使用泛型成為首選,那么如何判斷泛型參數(shù)的具體數(shù)據(jù)類型并進行有效轉(zhuǎn)換呢?
比如下面的例子:
[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 }
定義了一個名叫「屬性」的結(jié)構(gòu)體,包含標簽,具體值和屬性類別(是主屬性還是副屬性),并使用泛型約束數(shù)據(jù)為值類型。
現(xiàn)在想要快速對這個結(jié)構(gòu)體進行加法操作,于是增加操作符重載函數(shù),方便愉快的對兩個屬性的值相加,但問題是泛型是無法強轉(zhuǎn)為任何一種非object數(shù)據(jù)類型,直接相加則更是不可能。
這時就想到了以object類型作為橋梁,進行具體的類型判定與轉(zhuǎn)換:
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關(guān)鍵字,也可直接取得值的類型或泛型類型進行判定:
if (tempa.GetType() == typeof(float)) { } //or if (typeof(T) == typeof(float)) { }
上面的方案雖然可以解決類型轉(zhuǎn)換的需求,但頻繁的拆箱和裝箱以及類型判定對性能的還是有一定影響,而且如果每一種類型都寫進if-else,看上去像千層塔一般難受。是時候輪到dynamic登場了。
.Net 4.0 以后開始支持動態(tài)數(shù)據(jù)類型——也就是dynamic關(guān)鍵字;令人興奮的是,dynamic可以被賦值為任何一種類型的值,當然也包括泛型。
然而值得注意的是,dynamic關(guān)鍵字并不會在程序編譯的時候進行校驗,而只在運行時動態(tài)判定,所以使用的時需要格外小心。
當然了,多次運行時的性能要遠遠高于裝箱和拆箱,而且書寫起來也是相當簡潔美觀(¯﹃¯):
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>(); }
可以直接執(zhí)行相加操作,但如果實際傳入的兩個數(shù)據(jù)類型并不能相加如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, (T)(x1 + x2), a.Type); } } return new Property<T>(); }
補充一句,dynamic關(guān)鍵字在Unity中可能會報錯,因為Unity默認用的是.Net Api為2.0版本,需要升級為4.0之后的版本才能使用該關(guān)鍵字,具體設置如下:
下面做一個簡單測試:
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# 泛型中的數(shù)據(jù)類型判定與轉(zhuǎn)換的詳細內(nèi)容,更多關(guān)于C# 泛型 數(shù)據(jù)類型判定與轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c#異步操作async?await狀態(tài)機的總結(jié)(推薦)
這篇文章主要介紹了c#異步操作async?await狀態(tài)機的總結(jié),關(guān)于async和await每個人都有自己的理解,甚至關(guān)于異步和同步亦或者關(guān)于異步和多線程每個人也都有自己的理解,本文通過實例代碼詳細講解,需要的朋友可以參考下2023-02-02C#判斷一個字符串是否是數(shù)字或者含有某個數(shù)字的方法
這篇文章主要介紹了C#判斷一個字符串是否是數(shù)字或者含有某個數(shù)字的方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2018-06-06c# 使用特定帳號密碼訪問Windows網(wǎng)路共享
這篇文章主要介紹了c# 使用特定帳號密碼訪問Windows網(wǎng)路共享的方法,幫助大家更好的理解和學習使用c#,感興趣的朋友可以了解下2021-03-03