C#中的枚举类型约束

时间:2009-08-26 00:26:58

标签: c# .net enums

  

可能重复:
  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
{
...
}

6 个答案:

答案 0 :(得分:145)

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

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,以防止非枚举的继承版本。

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

答案 1 :(得分:92)

这是偶尔要求的功能。

正如我喜欢指出的那样,所有功能都没有实现,直到有人设计,规格,工具,测试,文档和发布功能。到目前为止,没有人为此做过。没有特别不寻常的原因;我们还有许多其他的事情要做,预算有限,而且这个从来没有超越过“这不是很好吗?”语言设计团队的讨论。

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

我可以看到有一些不错的使用案例,但是没有一个是如此引人注目,以至于我们做了这项工作,而不是更频繁要求的数百个其他功能之一,或者更具吸引力更远的用例。 (如果我们要使用这段代码,我会亲自优先考虑委托约束方式,比上面的枚举约束。)

答案 2 :(得分:15)

public static T GetEnum<T>(this string description) where T : struct
{
    return (T)Enum.Parse(typeof(T), description);
}

它能回答你的问题吗?

答案 3 :(得分:7)

IL编织使用ExtraConstraints

您的代码

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

编译什么

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

答案 4 :(得分:3)

这是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

答案 5 :(得分:2)

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

枚举的“base”类型E,我的意思是System命名空间中的类型,其名称与获得的System.TypeCode枚举成员的名称相同致电System.Type.GetTypeCode(System.Type)获取E类型。如果枚举是在C#中声明的,那么它与声明为“继承”的类型相同(我不确定这是在规范中正式调用的)。例如,以下Animal枚举的基本类型为System.Byte

public enum Animal : byte
{
    Moose,
    Squirrel
}

可以使用switch语句编写这样的方法,但肯定是丑陋的,你不能获得强类型参数或类型是枚举的基本类型的返回类型,你必须重复元数据查找或做一些缓存(例如在包含该方法的泛型类型的静态构造函数中)。