將C#裡的列舉Enum轉換為int
阿新 • • 發佈:2019-01-08
將列舉型別轉換為int在C#裡非常簡單,直接(int)強轉就行了,可是這樣寫程式碼不方便,尤其讓我這種懶癌患者難受,我喜歡用擴充套件方法的方式實現轉換(如果不理解擴充套件方法請自行補課,這裡不再介紹),比如這樣string轉int:
public static class ExtendString
{
public static int ToInt(this string s, int defaultValue = 0)
{
int i;
return int.TryParse(s, out i) ? i : defaultValue;
}
}
比什麼Convert或者Parse不知道高到哪裡去了:
string str = "123";
int i = str.ToInt();
同樣處理Enum行不行?
public static class ExtendEnum
{
public static int ToInt(this System.Enum e)
{
return (int)e;
}
}
很可惜Enum型別的實參可以強轉為int,但是形參不行,編譯器提示無法轉換型別,非常令人無語。
不過用個object做中介就能強轉了:
public static int ToInt(this System.Enum e)
{
return (int)(object)e;
}
這時我們的列舉變數都可以呼叫ToInt()了,貌似一切都成功了。
身為本文作者的我敏銳的發現這種做法有個致命缺陷——裝箱,它是程式碼效能驟降的一大元凶,我們要盡力避免它的存在。
先嚐試改動轉換方法:
public static int ToInt(this System.Enum e)
{
return System.Convert.ToInt32(e);
}
結果發現e是以object型別被傳參的,跟前一種做法相比沒有本質區別。
思考良久我突然靈光一閃:任何物件都有 GetHashCode() 方法,用於返回該物件資料的Hash值,C#的常見內部型別都各自過載了該方法,比如int物件返回的Hash值就是它的數值本身,同為整型資料的Enum應該也返回它的數值才對。
為了防止搞出烏龍,那就查一下Enum類的原始碼吧,下面我把GetHashCode()的原始碼貼出來:
[System.Security.SecuritySafeCritical]
public override unsafe int GetHashCode()
{
// Avoid boxing by inlining GetValue()
// return GetValue().GetHashCode();
fixed (void* pValue = &JitHelpers.GetPinningHelper(this).m_data)
{
switch (InternalGetCorElementType())
{
case CorElementType.I1:
return (*(sbyte*)pValue).GetHashCode();
case CorElementType.U1:
return (*(byte*)pValue).GetHashCode();
case CorElementType.Boolean:
return (*(bool*)pValue).GetHashCode();
case CorElementType.I2:
return (*(short*)pValue).GetHashCode();
case CorElementType.U2:
return (*(ushort*)pValue).GetHashCode();
case CorElementType.Char:
return (*(char*)pValue).GetHashCode();
case CorElementType.I4:
return (*(int*)pValue).GetHashCode();
case CorElementType.U4:
return (*(uint*)pValue).GetHashCode();
case CorElementType.R4:
return (*(float*)pValue).GetHashCode();
case CorElementType.I8:
return (*(long*)pValue).GetHashCode();
case CorElementType.U8:
return (*(ulong*)pValue).GetHashCode();
case CorElementType.R8:
return (*(double*)pValue).GetHashCode();
case CorElementType.I:
return (*(IntPtr*)pValue).GetHashCode();
case CorElementType.U:
return (*(UIntPtr*)pValue).GetHashCode();
default:
Contract.Assert(false, "Invalid primitive type");
return 0;
}
}
}
果然是強轉為int後再GetHashCode(),等價於強轉int
再看看最頂上的註釋,我跟微軟英雄所見略同啊哈哈
所以最後得到的程式碼為:
public static class ExtendEnum
{
public static int ToInt(this System.Enum e)
{
return e.GetHashCode();
}
}
結束