C# 如何将泛型类型参数限制为System.Enum

C# 如何将泛型类型参数限制为System.Enum,c#,.net,vb.net,enums,C#,.net,Vb.net,Enums,可能的重复项: 是否可以将泛型类型参数[我不知道这是否是正确的名称]限制为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&

可能的重复项:

是否可以将泛型类型参数[我不知道这是否是正确的名称]限制为
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());
}
//VB.NET
函数GetValues(作为System.Enum的T的)(ByVal值作为T的)作为IEnumerable(作为T的)
返回[Enum].GetValues(value.GetType)
端函数
//C#
公共IEnumerable GetValues(T值),其中T:System.Enum
{
返回Enum.GetValues(value.GetType());
}

更新


我最终用了乔恩·斯基特的。感谢你们所有人的贡献。

你们不能。另一种解决方案是使用
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()); 
} 
public IEnumerable GetValues(T值),其中T:struct
{  
如果(!typeof(T).IsEnum)抛出新的NotSupportedException();
返回(IEnumerable)Enum.GetValues(value.GetType());
} 

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

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

using System.Linq;
.
.
.
public IEnumerable<Enum> GetValues(Enum value)
{
    return Enum.GetValues(value.GetType()).OfType<Enum>();
}
使用System.Linq;
.
.
.
公共IEnumerable GetValues(枚举值)
{
返回类型()的Enum.GetValues(value.GetType());
}

很遗憾,您不能-


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

Matt和Danny的答案都有一半的答案。这实际上可以满足您的需求:

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>(); 
} 
public IEnumerable GetValues(),其中T:struct
{   
如果(!typeof(T).IsEnum)抛出新的InvalidOperationException(“泛型类型参数不是System.Enum”);
返回类型()的Enum.GetValues(typeof(T));
} 
与Danny的答案不同:

  • 尽管拥有泛型类型的参数允许进行类型推断,但由于实际未使用该值,因此更适合显式指定泛型类型(与不接受参数的Linq方法类似)
  • GetValues()返回一个对象数组,该数组不会隐式转换为T的IEnumerable。转换结果的额外Linq方法(从技术上讲,OfType是一个筛选操作,但在本例中它将返回所有内容)是符合返回类型所必需的
  • 可选:尽管NotSupportedException是抛出异常的最佳选择,但还有其他选项;ArgumentException、InvalidOperationException、InvalidCastException等等。我选择InvalidOperationException是因为它就是这样;从非枚举类型获取枚举值的尝试无效。这是语义上的,我不会和其他人的逻辑争论

为什么不直接使用枚举而不是泛型?另一个可能的重复:在这里投票支持它,然后等待十年,等待C#团队来处理它。+马丁·布朗,你把C#和Java混淆了:)不幸的是,这不是传入的枚举的强类型;您将得到一个包含System.Enum的列表,然后您必须将其转换为正确的类型。@KeithS:正如您对Danny Chen的答案和OP的原始代码所做的那样(事实上,这甚至不起作用,因为
数组
不是泛型的)。否。泛型返回该特定枚举类型的值的强类型列表;不需要强制转换返回类型(除非需要数字或字符串等)。但是,由于其他原因,his不起作用。即使编译,也不会返回所需的结果
Enum.GetValues
返回一个
数组
(其元素只是对象),该数组不会隐式强制转换为
IEnumerable
。不幸的是,您的解决方案不会返回一个通用的可枚举列表。不过,这给了我一些见解。谢谢。顺便说一句,我实现了你的解决方案,并且是为了一个不同的,虽然相关的目的。为什么不使用Cast方法呢
return Enum.GetValues(typeof(T)).Cast()
在这种情况下,它可能会起作用,但是在这个网站上有几个问题是关于它不能按用户期望的方式工作的情况。我更倾向于避免使用OfType或Select,这将以一种明确的方式完成工作。顺便说一句,我实现了您的解决方案,并出于一个不同但相关的目的。感谢您指出Jon Skeet的无约束旋律。这非常有用。C#7.3实际上增加了通过枚举直接约束泛型约束的功能-