将C#里的枚举Enum转换为int

xiaoxiao2021-02-27  293

将枚举类型转换为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(); } }结束

转载请注明原文地址: https://www.6miu.com/read-3944.html

最新回复(0)