任何人都知道缺乏枚举通用约束的好方法吗?

Kei*_*ith 87 .net c# enums flags

我想要做的是这样的:我有枚举标记值的枚举.

public static class EnumExtension
{
    public static bool IsSet<T>( this T input, T matchTo ) 
        where T:enum //the constraint I want that doesn't exist in C#3
    {    
        return (input & matchTo) != 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

那么我可以这样做:

MyEnum tester = MyEnum.FlagA | MyEnum.FlagB

if( tester.IsSet( MyEnum.FlagA ) )
    //act on flag a
Run Code Online (Sandbox Code Playgroud)

不幸的是,C#的通用,其中约束没有枚举限制,只有类和结构.C#不会将枚举视为结构(即使它们是值类型),因此我无法像这样添加扩展类型.

有没有人知道解决方法?

Jon*_*eet 48

编辑:这是现在的UnconstrainedMelody版本0.0.0.2.

(根据我在博客文章中关于枚举约束的要求.为了获得独立答案,我已经在下面列出了基本事实.)

最好的解决方案是等待我将其包含在UnconstrainedMelody 1中.这是一个带有C#代码的库,其中包含"假"约束

where T : struct, IEnumConstraint
Run Code Online (Sandbox Code Playgroud)

把它变成了

where T : struct, System.Enum
Run Code Online (Sandbox Code Playgroud)

通过postbuild步骤.

它不应该太难写IsSet......虽然迎合了既Int64基于和UInt64基于标志可能是棘手的部分.(我闻到了一些辅助方法,基本上允许我处理任何标志枚举,就好像它有一个基本类型UInt64.)

如果你打电话,你想要的行为是什么?

tester.IsSet(MyFlags.A | MyFlags.C)
Run Code Online (Sandbox Code Playgroud)

?它应该检查是否设置了所有指定的标志?那是我的期望.

我会在今晚回家的路上尝试这样做...我希望快速闪现有用的枚举方法,让图书馆快速达到可用的标准,然后放松一下.

编辑:IsSet顺便说一下,我不确定这个名字.选项:

  • 包括
  • 包含
  • HasFlag(或HasFlags)
  • IsSet(它当然是一个选项)

欢迎思考.不管怎么说,我确定它还有一段时间才能结束.


1,或者将其作为补丁提交,当然......

  • 从C#7.3(2018年5月发布)开始,可以使用约束条件``where T:System.Enum`''。这已经在线程的其他地方编写了;只是以为我会在这里重复一遍。 (3认同)

Iva*_*rić 17

从C#7.3开始,现在有一种内置的方法来添加枚举约束:

public class UsingEnum<T> where T : System.Enum { }
Run Code Online (Sandbox Code Playgroud)

来源:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint


Ron*_*nie 16

Darren,如果类型是特定的枚举,它将起作用 - 对于一般的枚举工作,你必须将它们转换为int(或更可能是uint)来进行布尔数学运算:

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
Run Code Online (Sandbox Code Playgroud)


SLa*_*aks 9

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

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.IsSet<DateTimeKind>("Local")
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以Enums<Temp>使用Tempas 提供私有构造函数和公共嵌套抽象继承类Enum,以防止非枚举的继承版本.


Sim*_*mon 8

您可以使用IL Weaving和ExtraConstraints实现此目的

允许您编写此代码

public class Sample
{
    public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
    {        
    }
    public void MethodWithEnumConstraint<[EnumConstraint] T>()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

什么被编译

public class Sample
{
    public void MethodWithDelegateConstraint<T>() where T: Delegate
    {
    }

    public void MethodWithEnumConstraint<T>() where T: struct, Enum
    {
    }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*Mik 7

从 C# 7.3 开始,您可以对泛型类型使用 Enum 约束:

public static TEnum Parse<TEnum>(string value) where TEnum : Enum
{
    return (TEnum) Enum.Parse(typeof(TEnum), value);
}
Run Code Online (Sandbox Code Playgroud)

如果要使用 Nullable 枚举,则必须保留原始结构约束:

public static TEnum? TryParse<TEnum>(string value) where TEnum : struct, Enum
{
    if( Enum.TryParse(value, out TEnum res) )
        return res;
    else
        return null;
}
Run Code Online (Sandbox Code Playgroud)