C#中的枚举类型约束[重复]

Posted

技术标签:

【中文标题】C#中的枚举类型约束[重复]【英文标题】:Enum type constraints in C# [duplicate] 【发布时间】:2009-08-26 00:26:58 【问题描述】:

可能重复:Anyone know a good workaround for the lack of an enum generic constraint?

C# 不允许对Enum 进行类型约束的原因是什么?我敢肯定,这种疯狂背后有一种方法,但我想了解为什么它是不可能的。

以下是我希望能够做到的(理论上)。

public static T GetEnum<T>(this string description) where T : Enum

...

【问题讨论】:

另见***.com/questions/7244 另见***.com/questions/1404077/… @thecoop - 您发布的可能与 Keith 发布的相同。 对于任何想知道这将在 C# 7.3 中出现的人:docs.microsoft.com/en-us/visualstudio/releasenotes/…。 【参考方案1】:

实际上,这是可能的,但有一个丑陋的把戏。 但是,它不能用于扩展方法。

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&lt;Temp&gt;一个私有构造函数和一个公共嵌套抽象继承类Temp作为Enum,以防止非枚举的继承版本。

请注意,您不能使用此技巧来制作扩展方法。

【讨论】:

这确实适用于代表,但它不会排除 Delegate 本身。 更优雅的方式:***.com/questions/1331739/enum-type-constraints-in-c/… @bsnote:这并不妨碍你在编译时传递intDateTime 这真是太棒了,不,@bsnote,对于可以进行编译时检查的情况,运行时检查永远不会比编译时检查好。 @hypehuman:防止您使用Enums&lt;SomeOtherType&gt;objectValueType 除外)。这些是唯一符合 : class 并具有符合 : struct 的子类型的类型。【参考方案2】:

这是一个偶尔需要的功能。

正如我喜欢指出的那样,在有人设计、规范、实施、测试、记录并发布该功能之前,所有功能都未实现。到目前为止,没有人为此做过。没有什么特别不寻常的理由。我们还有很多其他事情要做,预算有限,而这件事从来没有超过“这不是很好吗?”语言设计团队的讨论。

CLR 不支持它,所以为了让它工作,除了语言工作之外,我们还需要做运行时工作。(见答案 cmets)

我可以看到有一些不错的使用案例,但没有一个比其他数百个更频繁请求的功能之一更引人注目,或者更具吸引力和更广泛的使用案例。 (如果我们要处理这段代码,我个人会优先考虑委托约束,远高于枚举约束。)

【讨论】:

CLR 确实支持它,至少根据我对规范第 166 页的理解。 以前不知何故错过了这篇文章。在另一个问题中,此博客文章已链接:The Case of the Missing Generic (Parse Method) 这表明它在 IL 中可用。我似乎记得以前尝试过它并且它有效,尽管那可能是Delegate。如果这可能意味着从 C# 5 中删除了限制,我会很乐意尝试更多(哎呀,更多)。(我假设 C# 4 现在被锁定了。) 我很困惑为什么您声明 CLR 不支持 Enum 约束,因为它根据 CLI ECMA 文档的第 166/167 页 (ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf) 支持(也就是说,除非CLR 不符合 CLI 规范)和 Jon Skeet 在 Unconstrained Melody (code.google.com/p/unconstrained-melody) 中的工作。 那么,问问自己更有可能的是什么?规范是错误的并且 Jon 的实现是虚构的,或者我记错了或误解了一年多前我与 CLR 人员就此进行的对话? FWIW,C# 7.3 adds enum constraints【参考方案3】:
public static T GetEnum<T>(this string description) where T : struct

    return (T)Enum.Parse(typeof(T), description);

它回答了你的问题吗?

【讨论】:

不!问题是关于将类型参数 T 缩小到 Enum。 'struct' 过于宽泛,包括 int、float、double、DateTime 和其他类型,甚至可以由用户定义为结构。 您可以根据需要进行运行时检查。我做了: !typeof(T).IsEnum 是的!正是我编写通用方法所需要的。进一步限制直接枚举会很好,但我认为在大多数情况下并非绝对必要。 我在第一行做了这样的事情:if (!typeof(T).IsEnum) throw new InvalidOperationException("MethodBlah requires an enum!"); 【参考方案4】:

使用ExtraConstraints 进行IL 编织

您的代码

public static T GetEnum<[EnumConstraint] T>(this string description)

    ...

编译的内容

public static T GetEnum<T>(this string description) where T : Enum

    ...

【讨论】:

去@Simon,你到github.com/SimonCropp/ExtraConstraints的链接已经失效。看看历史,它应该指向github.com/Fody/ExtraConstraints吗?它说最后一次提交是 SimonCropp 1 个月前... @WaiHaLee 谢谢。链接固定【参考方案5】:

这是SLaks excellent ugly trick 的VB.NET 版本,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

输出:

Local = 2
IsDefined(Local) = True
IsDefined(4) = False
 ReadWrite same as Read Or Write: True

【讨论】:

【参考方案6】:

这里有一件奇怪的事情是,您可能想要编写相当多的通用 Enum 方法,它们的实现取决于枚举的“基本”类型。

枚举的“基”类型E是指System命名空间中的类型,其名称与调用System.Type.GetTypeCode(System.Type)获得的System.TypeCode枚举成员的名称相同类型E。如果枚举是在 C# 中声明的,则它与声明为“继承”的类型相同(我不确定规范中的正式名称是什么)。比如下面Animal枚举的基类型是System.Byte

public enum Animal : byte

    Moose,
    Squirrel

可以使用 switch 语句编写这样的方法,但它确实很难看,你无法获得强类型参数或类型为枚举基类型的返回类型,你必须重复元数据查找或做一些缓存(例如在包含该方法的泛型类型的静态构造函数中)。

【讨论】:

以上是关于C#中的枚举类型约束[重复]的主要内容,如果未能解决你的问题,请参考以下文章

(C#) 如class Demo<T,V> where T:这里如何约束T只能是枚举类型

在 C# 中使用枚举作为泛型类型参数 [重复]

C# 枚举器和可枚举类型

c#中的数据类型简介(枚举)

自定义枚举作为 C# 中的应用程序设置类型?

c#中怎样定义枚举?