如何将泛型类型参数限制为 System.Enum [重复]

Posted

技术标签:

【中文标题】如何将泛型类型参数限制为 System.Enum [重复]【英文标题】:How to limit a generic type parameter to System.Enum [duplicate] 【发布时间】:2011-02-21 15:23:25 【问题描述】:

可能的重复:Anyone know a good workaround for the lack of an enum generic constraint?Create Generic method constraining T to an Enum

是否可以将泛型类型参数 [我不知道这是否是正确的名称] 限制为 Enum

例如,我该如何做这样的事情?

//VB.NET
Function GetValues(Of T As System.Enum)(ByVal value As T) As IEnumerable(Of T)
    Return [Enum].GetValues(value.GetType)
End Function

//C#
public IEnumerable<T> GetValues<T>(T value) where T : System.Enum

    return Enum.GetValues(value.GetType());


更新

我最终为此使用了 Jon Skeet 的 Unconstrained Melody。感谢大家的贡献。

【问题讨论】:

为什么不直接使用枚举而不是泛型?? 另一个可能的重复:Create Generic method constraining T to an Enum 在这里投票 visualstudio.uservoice.com/forums/121579-visual-studio/… 然后等待 C# 团队解决它十年。 +Martin Brown,你把 C# 和 Java 搞混了 :) 【参考方案1】:

你不能。另一种解决方案是使用struct 和运行时检查。

public IEnumerable<T> GetValues<T>(T value) where T : struct
  
    if (!typeof(T).IsEnum) throw new NotSupportedException();
    return (IEnumerable<T>)Enum.GetValues(value.GetType()); 
 

【讨论】:

即使编译也不会返回所需的结果。 Enum.GetValues 返回一个 Array(其元素只是对象),它不会隐式转换为 IEnumerable&lt;T&gt; 不幸的是,您的解决方案不会返回一个通用的可枚举列表。不过,它为我提供了一些见解。谢谢。 顺便说一句,我实现了您的解决方案和 @Keiths' 用于不同但相关的目的。【参考方案2】:

很遗憾,您不能 - Microsoft closed this one out as a won't fix item。

您可以将枚举视为结构并将其用作约束(我认为 Jon Skeet 在Unconstrained Melody 中就是这样做的?)但这有点难看。

【讨论】:

感谢您指出 Jon Skeet 的不受约束的旋律。这很有帮助。 C# 7.3 实际上添加了通过枚举直接约束通用约束的能力 - source【参考方案3】:

马特和丹尼的答案都有一半。这实际上应该可以满足您的需求:

public IEnumerable<T> GetValues<T>() where T : struct
   
    if (!typeof(T).IsEnum) throw new InvalidOperationException("Generic type argument is not a System.Enum");
    return Enum.GetValues(typeof(T)).OfType<T>(); 
 

与丹尼的回答不同:

虽然具有泛型类型的参数允许进行类型推断,但由于实际并未使用该值,因此显式指定泛型类型更为合适(例如不带参数的 Linq 方法)。 Enum.GetValues() 返回一个对象数组,它不会隐式转换为 T 的 IEnumerable。用于转换结果的额外 Linq 方法(技术上 OfType 是一个过滤操作,但在这种情况下它将返回所有内容)必须符合返回类型。 可选:虽然 NotSupportedException 是抛出异常的最佳选择,但还有其他选择; ArgumentException、InvalidOperationException、InvalidCastException 等。我选择 InvalidOperationException 是因为它就是这样;从非枚举类型获取枚举值的无效尝试。这是语义上的,我不会与任何人的逻辑争论。

【讨论】:

为什么不直接使用 Cast 方法呢? return Enum.GetValues(typeof(T)).Cast&lt;T&gt;() 它可能会在这种情况下工作,但是在这个网站上有几个问题处理它不能按用户期望的方式工作的情况。我宁愿避免使用 OfType 或 Select,它会以明确的方式完成这项工作。 顺便说一句,我实现了您的解决方案和 @Danny Chen's 用于不同但相关的目的。【参考方案4】:

没有必要以这种方式使您的方法通用。

您可以只使用System.Enum 作为返回类型中的类型参数:

using System.Linq;
.
.
.
public IEnumerable<Enum> GetValues(Enum value)

    return Enum.GetValues(value.GetType()).OfType<Enum>();

【讨论】:

不幸的是,这不是对传入的 Enum 的强类型;你会得到一个包含 System.Enums 的列表,然后你必须将其转换为正确的类型。 @KeithS:就像您对 Danny Chen 的回答和 OP 的原始代码一样(实际上,这甚至行不通,因为 Array 不是通用的)。 没有。泛型返回该特定枚举类型的强类型值列表;不需要转换返回类型(除非您想要数字或字符串等)。但是,由于其他原因,他的不起作用。

以上是关于如何将泛型类型参数限制为 System.Enum [重复]的主要内容,如果未能解决你的问题,请参考以下文章

可以将泛型类型限制为枚举吗? [复制]

当两个类型参数在C#中实现公共接口时,如何将泛型强制转换为它实现的接口

将泛型限制为可以为空的事物

是否存在将我的泛型方法限制为数字类型的约束?

将泛型参数与 impl 中的关联类型匹配

将泛型类型转换为具体类型时出错