【问题标题】:How to limit a generic type parameter to System.Enum [duplicate]如何将泛型类型参数限制为 System.Enum [重复]
【发布时间】: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。感谢大家的贡献。

【问题讨论】:

标签: c# .net vb.net enums


【解决方案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 不是通用的)。
  • 没有。泛型返回该特定枚举类型的强类型值列表;不需要转换返回类型(除非您想要数字或字符串等)。但是,由于其他原因,他的不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
  • 2016-10-28
  • 2021-06-27
相关资源
最近更新 更多