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

时间:2022-04-05 16:27:58

Possible Duplicates:
Anyone know a good workaround for the lack of an enum generic constraint?
Create Generic method constraining T to an Enum

可能重复:任何人都知道缺少枚举通用约束的好方法?创建将T限制为枚举的通用方法

Is is possible to limit the generic type parameter [I don't know if that's the right name] to an Enum?

是否可以将枚举的泛型类型参数[我不知道这是否是正确的名称]?

For example how do I do something like this?

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

//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());
}

Update

更新

I eventually used Jon Skeet's Unconstrained Melody for that purpose. Thanks to you all for your contributions.

我最终为此目的使用了Jon Skeet的无约束旋律。感谢大家的贡献。

4 个解决方案

#1


7  

Unfortunately, you cannot - Microsoft closed this one out as a won't fix item.

不幸的是,你不能 - 微软关闭这个作为一个不会修复项目。

You can treat enums as structs and use that as the constraint instead (I think that was how Jon Skeet did it in Unconstrained Melody?) but that is kind of unsightly.

您可以将枚举视为结构并将其用作约束(我认为Jon Skeet是如何在Unconstrained Melody中完成的?)但这有点不雅观。

#2


16  

You can't. An alternative solution is using struct and run-time check.

你不能。另一种解决方案是使用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()); 
} 

#3


5  

Matt's and Danny's answers both have half the answer. This should actually get you what you need:

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>(); 
} 

Changes from Danny's answer:

Danny回答的变化:

  • Though having a parameter of the generic type allows for type inference, since the value is not actually used it is more proper to explicitly specify the generic type (like with the Linq methods that don't take parameters).
  • 虽然具有泛型类型的参数允许类型推断,但由于实际上没有使用该值,因此更明确地指定泛型类型更合适(就像使用不带参数的Linq方法一样)。
  • Enum.GetValues() returns an Array of Objects, which will not cast implicitly to an IEnumerable of T. The extra Linq method to cast the results (technically OfType is a filter operation but in this case it'll return everything) is necessary to conform to the return type.
  • Enum.GetValues()返回一个对象数组,它不会隐式地转换为T的IEnumerable。用于转换结果的额外Linq方法(技术上OfType是一个过滤操作,但在这种情况下它将返回所有内容)是必要的符合退货类型。
  • Optional: though NotSupportedException is as good a choice as any for an exception to throw, there are other options; ArgumentException, InvalidOperationException, InvalidCastException, etc. I chose InvalidOperationException because that's what it is; an invalid attempt to get enum values from a non-enum type. This is semantic and I'm not going to argue with anyone else's logic.
  • 可选:尽管NotSupportedException与抛出异常的选择一样好,但还有其他选项; ArgumentException,InvalidOperationException,InvalidCastException等。我选择了InvalidOperationException,因为它就是这样;无效尝试从非枚举类型获取枚举值。这是语义的,我不会与其他任何人的逻辑争论。

#4


2  

There is no need to make your method generic in this way.

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

You can just use the System.Enum as the type parameter in your return type:

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

using System.Linq;
.
.
.
public IEnumerable<Enum> GetValues(Enum value)
{
    return Enum.GetValues(value.GetType()).OfType<Enum>();
}

#1


7  

Unfortunately, you cannot - Microsoft closed this one out as a won't fix item.

不幸的是,你不能 - 微软关闭这个作为一个不会修复项目。

You can treat enums as structs and use that as the constraint instead (I think that was how Jon Skeet did it in Unconstrained Melody?) but that is kind of unsightly.

您可以将枚举视为结构并将其用作约束(我认为Jon Skeet是如何在Unconstrained Melody中完成的?)但这有点不雅观。

#2


16  

You can't. An alternative solution is using struct and run-time check.

你不能。另一种解决方案是使用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()); 
} 

#3


5  

Matt's and Danny's answers both have half the answer. This should actually get you what you need:

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>(); 
} 

Changes from Danny's answer:

Danny回答的变化:

  • Though having a parameter of the generic type allows for type inference, since the value is not actually used it is more proper to explicitly specify the generic type (like with the Linq methods that don't take parameters).
  • 虽然具有泛型类型的参数允许类型推断,但由于实际上没有使用该值,因此更明确地指定泛型类型更合适(就像使用不带参数的Linq方法一样)。
  • Enum.GetValues() returns an Array of Objects, which will not cast implicitly to an IEnumerable of T. The extra Linq method to cast the results (technically OfType is a filter operation but in this case it'll return everything) is necessary to conform to the return type.
  • Enum.GetValues()返回一个对象数组,它不会隐式地转换为T的IEnumerable。用于转换结果的额外Linq方法(技术上OfType是一个过滤操作,但在这种情况下它将返回所有内容)是必要的符合退货类型。
  • Optional: though NotSupportedException is as good a choice as any for an exception to throw, there are other options; ArgumentException, InvalidOperationException, InvalidCastException, etc. I chose InvalidOperationException because that's what it is; an invalid attempt to get enum values from a non-enum type. This is semantic and I'm not going to argue with anyone else's logic.
  • 可选:尽管NotSupportedException与抛出异常的选择一样好,但还有其他选项; ArgumentException,InvalidOperationException,InvalidCastException等。我选择了InvalidOperationException,因为它就是这样;无效尝试从非枚举类型获取枚举值。这是语义的,我不会与其他任何人的逻辑争论。

#4


2  

There is no need to make your method generic in this way.

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

You can just use the System.Enum as the type parameter in your return type:

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

using System.Linq;
.
.
.
public IEnumerable<Enum> GetValues(Enum value)
{
    return Enum.GetValues(value.GetType()).OfType<Enum>();
}