詳解C# 泛型中的數(shù)據(jù)類型判定與轉(zhuǎn)換
提到類型轉(zhuǎn)換,首先要明確C#中的數(shù)據(jù)類型,主要分為值類型和引用類型:
1.常用的值類型有:(struct)
整型家族:int,byte,char,short,long等等一系列
浮點(diǎn)家族:float,double,decimal
孤獨(dú)的枚舉:enum
孤獨(dú)的布爾:bool
2.常用的引用類型有:
string,class,array,delegate,interface
值得注意的是,無(wú)論是值類型還是引用類型,在C#中都派生于object,沒(méi)錯(cuò),這家伙就是萬(wàn)惡之源!
正是因?yàn)橛辛诉@一特性,于是我們才能通過(guò)裝箱和拆箱愉快地將這些數(shù)據(jù)類型在值類型,object,引用類型間反復(fù)橫跳。
當(dāng)然了,無(wú)論是裝箱和拆箱,對(duì)于性能都是有消耗的,不到萬(wàn)不得已的時(shí)候盡量不要用(雖然我才不管這些,只要我用的爽就行了233)
雖然一般不提倡用object類型作為函數(shù)參數(shù),取而代之使用泛型成為首選,那么如何判斷泛型參數(shù)的具體數(shù)據(jù)類型并進(jìn)行有效轉(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) { //怎么知道這個(gè)值到底是int還是float... } return prop; } }
public enum PropertyType { Main, Sub }
定義了一個(gè)名叫「屬性」的結(jié)構(gòu)體,包含標(biāo)簽,具體值和屬性類別(是主屬性還是副屬性),并使用泛型約束數(shù)據(jù)為值類型。
現(xiàn)在想要快速對(duì)這個(gè)結(jié)構(gòu)體進(jìn)行加法操作,于是增加操作符重載函數(shù),方便愉快的對(duì)兩個(gè)屬性的值相加,但問(wèn)題是泛型是無(wú)法強(qiáng)轉(zhuǎn)為任何一種非object數(shù)據(jù)類型,直接相加則更是不可能。
這時(shí)就想到了以object類型作為橋梁,進(jìn)行具體的類型判定與轉(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>(); }
判定類型時(shí)可以使用is關(guān)鍵字,也可直接取得值的類型或泛型類型進(jìn)行判定:
if (tempa.GetType() == typeof(float)) { } //or if (typeof(T) == typeof(float)) { }
上面的方案雖然可以解決類型轉(zhuǎn)換的需求,但頻繁的拆箱和裝箱以及類型判定對(duì)性能的還是有一定影響,而且如果每一種類型都寫(xiě)進(jìn)if-else,看上去像千層塔一般難受。是時(shí)候輪到dynamic登場(chǎng)了。
.Net 4.0 以后開(kāi)始支持動(dòng)態(tài)數(shù)據(jù)類型——也就是dynamic關(guān)鍵字;令人興奮的是,dynamic可以被賦值為任何一種類型的值,當(dāng)然也包括泛型。
然而值得注意的是,dynamic關(guān)鍵字并不會(huì)在程序編譯的時(shí)候進(jìn)行校驗(yàn),而只在運(yùn)行時(shí)動(dòng)態(tài)判定,所以使用的時(shí)需要格外小心。
當(dāng)然了,多次運(yùn)行時(shí)的性能要遠(yuǎn)遠(yuǎn)高于裝箱和拆箱,而且書(shū)寫(xiě)起來(lái)也是相當(dāng)簡(jiǎn)潔美觀(¯﹃¯):
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í)際傳入的兩個(gè)數(shù)據(jù)類型并不能相加如bool,則會(huì)在運(yùn)行時(shí)報(bào)錯(cuò);當(dāng)然了,如果想進(jìn)一步防止安全,還可以增加更多的類型判定語(yǔ)句,如:
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>(); }
補(bǔ)充一句,dynamic關(guān)鍵字在Unity中可能會(huì)報(bào)錯(cuò),因?yàn)閁nity默認(rèn)用的是.Net Api為2.0版本,需要升級(jí)為4.0之后的版本才能使用該關(guān)鍵字,具體設(shè)置如下:
下面做一個(gè)簡(jiǎn)單測(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# 泛型中的數(shù)據(jù)類型判定與轉(zhuǎn)換的詳細(xì)內(nèi)容,更多關(guān)于C# 泛型 數(shù)據(jù)類型判定與轉(zhuǎn)換的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#?崩潰異常中研究頁(yè)堆布局的詳細(xì)過(guò)程
最近遇到一位朋友的程序崩潰,發(fā)現(xiàn)崩潰點(diǎn)在富編輯器 msftedit 上,這個(gè)不是重點(diǎn),重點(diǎn)在于發(fā)現(xiàn)他已經(jīng)開(kāi)啟了 頁(yè)堆,由于 頁(yè)堆 和 NT堆 的內(nèi)存布局完全不一樣,這一篇結(jié)合我的了解以及 windbg 驗(yàn)證來(lái)系統(tǒng)的介紹下 頁(yè)堆,需要的朋友可以參考下2022-10-10c#異步操作async?await狀態(tài)機(jī)的總結(jié)(推薦)
這篇文章主要介紹了c#異步操作async?await狀態(tài)機(jī)的總結(jié),關(guān)于async和await每個(gè)人都有自己的理解,甚至關(guān)于異步和同步亦或者關(guān)于異步和多線程每個(gè)人也都有自己的理解,本文通過(guò)實(shí)例代碼詳細(xì)講解,需要的朋友可以參考下2023-02-02C#實(shí)現(xiàn)對(duì)字符串進(jìn)行大小寫(xiě)切換的方法
這篇文章主要介紹了C#實(shí)現(xiàn)對(duì)字符串進(jìn)行大小寫(xiě)切換的方法,涉及C#操作字符串的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03C#判斷一個(gè)字符串是否是數(shù)字或者含有某個(gè)數(shù)字的方法
這篇文章主要介紹了C#判斷一個(gè)字符串是否是數(shù)字或者含有某個(gè)數(shù)字的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06C#實(shí)現(xiàn)將PDF轉(zhuǎn)為線性化PDF
線性化PDF文件是PDF文件的一種特殊格式,可以通過(guò)Internet更快地進(jìn)行查看。這篇文章主要介紹了如何通過(guò)C#實(shí)現(xiàn)將PDF轉(zhuǎn)為線性化PDF,感興趣的小伙伴可以學(xué)習(xí)一下2021-12-12c# 使用特定帳號(hào)密碼訪問(wèn)Windows網(wǎng)路共享
這篇文章主要介紹了c# 使用特定帳號(hào)密碼訪問(wèn)Windows網(wǎng)路共享的方法,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03