C#中的枚举types约束
可能重复:
任何人都知道一个很好的解决方法,缺乏枚举通用约束?
C#背后的原因是不允许Enum
的types限制? 我确信疯狂背后有一种方法,但我想明白为什么这是不可能的。
以下是我希望能够做到的(理论上)。
public static T GetEnum<T>(this string description) where T : Enum { ... }
这是一个偶尔要求的function。
正如我所指出的那样,除非有人devise,规格说明,实现,testing,文档和运送特征,否则所有function都是未实现的。 到目前为止,没有人为此做过这样的事情。 没有特别的原因,为什么不呢? 我们还有很多其他的事情要做,预算有限,而这个从来没有超过“这不好过吗? 在语言devise团队的讨论。
CLR不支持它,所以为了使其工作,除了语言工作之外,我们还需要做运行时工作。 (查看答案评论)
我可以看到有一些体面的使用案例,但没有一个是如此令人信服,以至于我们要做这个工作,而不是其他数百个要求更频繁的function之一,或者更具吸引力和更远的function使用情况。 (如果我们要使用这个代码,我会亲自优先考虑委托约束的方式,高于枚举约束。
事实上,这是可能的,一个丑陋的伎俩。 但是,它不能用于扩展方法。
public abstract class Enums<Temp> where Temp : class { public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp { return (TEnum)Enum.Parse(typeof(TEnum), name); } } public abstract class Enums : Enums<Enum> { } Enums.Parse<DateTimeKind>("Local")
如果你愿意,你可以给Enums<Temp>
一个私有的构造函数和一个Temp
为Enum
的公共嵌套抽象inheritance类,以防止非枚举的inheritance版本。
请注意,你不能使用这个技巧来制作扩展方法。
public static T GetEnum<T>(this string description) where T : struct { return (T)Enum.Parse(typeof(T), description); }
它回答你的问题吗?
这里有一个VB.NET版本的SLaks的优秀丑陋的把戏 , Imports
为“typedef”:(types推断按预期工作,但是你不能得到扩展方法。)
'Base namespace "EnumConstraint" Imports Enums = EnumConstraint.Enums(Of System.Enum) Public NotInheritable Class Enums(Of Temp As Class) Private Sub New() End Sub Public Shared Function Parse(Of TEnum As {Temp, Structure})(ByVal Name As String) As TEnum Return DirectCast([Enum].Parse(GetType(TEnum), Name), TEnum) End Function Public Shared Function IsDefined(Of TEnum As {Temp, Structure})(ByVal Value As TEnum) As Boolean Return [Enum].IsDefined(GetType(TEnum), Value) End Function Public Shared Function HasFlags(Of TEnum As {Temp, Structure})(ByVal Value As TEnum, ByVal Flags As TEnum) As Boolean Dim flags64 As Long = Convert.ToInt64(Flags) Return (Convert.ToInt64(Value) And flags64) = flags64 End Function End Class Module Module1 Sub Main() Dim k = Enums.Parse(Of DateTimeKind)("Local") Console.WriteLine("{0} = {1}", k, CInt(k)) Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k)) k = DirectCast(k * 2, DateTimeKind) Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k)) Console.WriteLine(" {0} same as {1} Or {2}: {3} ", IO.FileAccess.ReadWrite, IO.FileAccess.Read, IO.FileAccess.Write, _ Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileAccess.Read Or IO.FileAccess.Write)) ' These fail to compile as expected: 'Console.WriteLine(Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess)) 'Console.WriteLine(Enums.HasFlags(Of IO.FileAccess)(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess)) If Debugger.IsAttached Then _ Console.ReadLine() End Sub End Module
输出:
Local = 2 IsDefined(Local) = True IsDefined(4) = False ReadWrite same as Read Or Write: True
IL使用ExtraConstraints编织
你的代码
public static T GetEnum<[EnumConstraint] T>(this string description) { ... }
什么被编译
public static T GetEnum<T>(this string description) where T : Enum { ... }
这里有一个古怪的事情,就是有相当数量的genericsEnum方法可能需要编写,其实现依赖于枚举的“基本”types。
E
,我的意思是System
名字空间中的types,它的名字与System.TypeCode
枚举成员的名字相同,通过调用System.Type.GetTypeCode(System.Type)
获得E
型。 如果枚举是在C#中声明的,这是它被声明为“inheritance”的相同types(我不确定这是什么在规范中正式调用)。 例如,下面的Animal
枚举的基types是System.Byte
:
public enum Animal : byte { Moose, Squirrel }
使用switch语句编写这样的方法是可能的,但是确实很难看,你不能得到types为枚举基types的强types参数或返回types,你必须重复元数据查找或者进行一些caching(例如,在包含该方法的genericstypes的静态构造函数中)。