C#中的枚举类型约束
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1331739/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Enum type constraints in C#
提问by Taylor Leese
Possible Duplicate:
Anyone know a good workaround for the lack of an enum generic constraint?
可能的重复:
有人知道缺少枚举通用约束的好方法吗?
What is the reason behind C# not allowing type constraints on Enum
's? I'm sure there is a method behind the madness, but I'd like to understand why it's not possible.
C# 不允许对Enum
's进行类型约束的原因是什么?我确信疯狂背后有一种方法,但我想了解为什么这是不可能的。
Below is what I would like to be able to do (in theory).
以下是我希望能够做的(理论上)。
public static T GetEnum<T>(this string description) where T : Enum
{
...
}
采纳答案by Eric Lippert
This is an occasionally requested feature.
这是偶尔请求的功能。
As I'm fond of pointing out, ALL features are unimplemented until someone designs, specs, implements, tests, documents and ships the feature. So far, no one has done that for this one. There's no particularly unusual reason why not; we have lots of other things to do, limited budgets, and this one has never made it past the "wouldn't this be nice?" discussion in the language design team.
正如我喜欢指出的那样,在有人设计、规范、实施、测试、记录和发布该功能之前,所有功能都未实现。到目前为止,还没有人为这一点做到这一点。没有什么特别不寻常的原因。我们还有很多其他事情要做,预算有限,而这件事从来没有超过“这不是很好吗?” 语言设计团队中的讨论。
The CLR doesn't support it, so in order to make it work we'd need to do runtime work in addition to the language work.(see answer comments)
CLR 不支持它,所以为了使它工作,除了语言工作之外,我们还需要做运行时工作。(见答案评论)
I can see that there are a few decent usage cases, but none of them are so compelling that we'd do this work rather than one of the hundreds of other features that are much more frequently requested, or have more compelling and farther-reaching usage cases. (If we're going to muck with this code, I'd personally prioritize delegate constraints way, way above enum constraints.)
我可以看到有一些不错的使用案例,但没有一个如此引人注目,以至于我们会做这项工作,而不是其他数百个更频繁请求的功能之一,或者具有更引人注目和更深远的功能使用案例。(如果我们要弄乱这段代码,我个人会优先考虑委托约束方式,远高于枚举约束。)
回答by SLaks
Actually, it is possible, with an ugly trick. However, it cannot be used for extension methods.
实际上,这是有可能的,但有一个丑陋的技巧。但是,它不能用于扩展方法。
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")
If you want to, you can give Enums<Temp>
a private constructor and a public nested abstract inherited class with Temp
as Enum
, to prevent inherited versions for non-enums.
如果需要,您可以Enums<Temp>
使用Temp
as提供一个私有构造函数和一个公共嵌套抽象继承类Enum
,以防止非枚举的继承版本。
Note that you can't use this trick to make extension methods.
请注意,您不能使用此技巧来制作扩展方法。
回答by Doug McClean
One quirky thing here is that there are a fair number of generic Enum methods you might want to write whose implementation depends on the "base" type of the enumeration.
这里一件奇怪的事情是,您可能想要编写相当多的通用 Enum 方法,它们的实现取决于枚举的“基本”类型。
By the "base" type of an enumeration, E
, I mean the type in the System
namespace whose name is the same as the name of the member of System.TypeCode
enumeration obtained by calling System.Type.GetTypeCode(System.Type)
for the type E
. If the enumeration was declared in C#, this is the same type that it was declared to "inherit" from (I'm not sure what this is officially called in the spec). For example, the base type of the Animal
enumeration below is System.Byte
:
通过枚举的“基本”类型E
,我指的是System
命名空间中的类型,其名称与System.TypeCode
通过调用System.Type.GetTypeCode(System.Type)
type获得的枚举成员的名称相同E
。如果枚举是在 C# 中声明的,这与它被声明为“继承”的类型相同(我不确定规范中的正式名称是什么)。例如,Animal
下面枚举的基本类型是System.Byte
:
public enum Animal : byte
{
Moose,
Squirrel
}
It's possible to write such methods using switch statements, but it sure is ugly, you can't get strongly typed parameters or return types whose type is the base type of the enumeration, and you have to either repeat the metadata lookup or do some caching (e.g. in the static constructor for the generic type containing the method).
可以使用 switch 语句编写这样的方法,但它确实很丑,您无法获得强类型参数或返回类型为枚举基本类型的类型,并且您必须重复元数据查找或进行一些缓存(例如,在包含该方法的泛型类型的静态构造函数中)。
回答by Andrei Sedoi
public static T GetEnum<T>(this string description) where T : struct
{
return (T)Enum.Parse(typeof(T), description);
}
Does it answer your question?
它回答你的问题吗?
回答by Mark Hurd
Here's a VB.NET version of SLaks excellent ugly trick, with Imports
as a "typedef":
(Type inference works as expected, but you can't get extension methods.)
这是 VB.NET 版本的SLaks 出色的丑陋技巧,Imports
作为“typedef”:(类型推断按预期工作,但您无法获得扩展方法。)
'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
Output:
输出:
Local = 2
IsDefined(Local) = True
IsDefined(4) = False
ReadWrite same as Read Or Write: True
回答by Simon
IL Weaving using ExtraConstraints
使用ExtraConstraints 的IL 编织
Your Code
你的代码
public static T GetEnum<[EnumConstraint] T>(this string description)
{
...
}
What gets compiled
什么被编译
public static T GetEnum<T>(this string description) where T : Enum
{
...
}