为所有枚举添加扩展方法,而不仅仅是特定种类
Adding extension methods for all enums, not just a specific kind
编辑:这个post不是重复的,那些其他的解决方案不允许我使用按位运算符。
我想做这样的事情:
public static class EnumExt
{
public static enum AddFlag(this enum e, enum flag) => e |= flag;
}
所以我可以这样使用它:
Color color = Red;
color.AddFlag(Color.Dark);
只是更容易阅读。 我希望这个单一方法适用于所有枚举值,而不是对我计划使用的每个枚举值进行覆盖。问题是,该代码不起作用,因为 enum
不是像 int
那样的类型。我尝试用泛型做一些事情:
public static class EnumExt
{
public static T AddFlag<T>(this T e, T flag)
where T : Enum // Can't constrain to Enum
{
return e = e | flag;
}
}
还有这个:
public static T AddFlag<T>(this T e, T flag)
where T : struct
{
if (!(typeof(T).IsEnum)) return default;
return e |= flag; // Operator '|' cannot be applied to T
}
其中有两个问题。因为它是 struct
这意味着此方法将显示 int
值。我使用 struct
只是因为它是最接近 Enum
的约束。如果它不是 Enum
,我将退出该方法,但这仍然不会让编译器知道 e
是 enum
,即使它应该始终在此时。
也尝试使用 where T : int
和转换,但 int
是无效的约束。
有什么办法可以做到吗?
编辑:我已经尝试了建议的两个答案来解决问题,但它们没有。带有 IEnumConstraint
的那个不起作用,因为它说我的 enum
没有继承它,而且这两个答案都不允许我实际做 return e |= flag;
// Doesn't work because C# won't allow bitwise operators on generic types
// Because the constraint is still vague enough for non-enum values to slip through
public static T AddFlag<T>(this T e, T flag)
where T : struct, IConvertible
// Doesn't work because enums don't inherit from IEnumConstraint
// Same as above
public static T AddFlag<T>(this T e, T flag)
where T : struct, IEnumConstraint
我的猜测是,即使这些确实仅限于 Enum
值,其他一些 class 仍然有可能继承自 IEnumConstraint
和 IConvertible
因此,按位运算符将不起作用,因为它仍然不能保证操作可用于 T
。
似乎唯一真正的解决方案是在 C# 7.3 中,它们允许您使用 System.Enum
作为约束。
能够弄清楚。我必须从 T
转换为 object
,然后转换为 int
,在 int
值上使用按位运算符,然后反转它以取回结果。
@mjwills 指出 C# 7.3 不会修复转换问题。它将修复的只是约束,我将能够删除抛出的异常。
public static T AddFlag<T>(this ref T e, T flag)
where T : struct, IConvertible
{
if (!(typeof(T).IsEnum)) throw new ArgumentException("Value must be an enum");
int added = (int)(object)e | (int)(object)flag;
e = (T)(object)added;
return e;
}
对 的一项可能改进是:
internal static class EnumExtensions
{
public static bool IsDefinedAndNotDefault<T>(this T value)
where T : Enum
{
return Enum.IsDefined(typeof(T), value) && !value.Equals(default(T));
}
}
编辑:这个post不是重复的,那些其他的解决方案不允许我使用按位运算符。
我想做这样的事情:
public static class EnumExt
{
public static enum AddFlag(this enum e, enum flag) => e |= flag;
}
所以我可以这样使用它:
Color color = Red;
color.AddFlag(Color.Dark);
只是更容易阅读。 我希望这个单一方法适用于所有枚举值,而不是对我计划使用的每个枚举值进行覆盖。问题是,该代码不起作用,因为 enum
不是像 int
那样的类型。我尝试用泛型做一些事情:
public static class EnumExt
{
public static T AddFlag<T>(this T e, T flag)
where T : Enum // Can't constrain to Enum
{
return e = e | flag;
}
}
还有这个:
public static T AddFlag<T>(this T e, T flag)
where T : struct
{
if (!(typeof(T).IsEnum)) return default;
return e |= flag; // Operator '|' cannot be applied to T
}
其中有两个问题。因为它是 struct
这意味着此方法将显示 int
值。我使用 struct
只是因为它是最接近 Enum
的约束。如果它不是 Enum
,我将退出该方法,但这仍然不会让编译器知道 e
是 enum
,即使它应该始终在此时。
也尝试使用 where T : int
和转换,但 int
是无效的约束。
有什么办法可以做到吗?
编辑:我已经尝试了建议的两个答案来解决问题,但它们没有。带有 IEnumConstraint
的那个不起作用,因为它说我的 enum
没有继承它,而且这两个答案都不允许我实际做 return e |= flag;
// Doesn't work because C# won't allow bitwise operators on generic types
// Because the constraint is still vague enough for non-enum values to slip through
public static T AddFlag<T>(this T e, T flag)
where T : struct, IConvertible
// Doesn't work because enums don't inherit from IEnumConstraint
// Same as above
public static T AddFlag<T>(this T e, T flag)
where T : struct, IEnumConstraint
我的猜测是,即使这些确实仅限于 Enum
值,其他一些 class 仍然有可能继承自 IEnumConstraint
和 IConvertible
因此,按位运算符将不起作用,因为它仍然不能保证操作可用于 T
。
似乎唯一真正的解决方案是在 C# 7.3 中,它们允许您使用 System.Enum
作为约束。
能够弄清楚。我必须从 T
转换为 object
,然后转换为 int
,在 int
值上使用按位运算符,然后反转它以取回结果。
@mjwills 指出 C# 7.3 不会修复转换问题。它将修复的只是约束,我将能够删除抛出的异常。
public static T AddFlag<T>(this ref T e, T flag)
where T : struct, IConvertible
{
if (!(typeof(T).IsEnum)) throw new ArgumentException("Value must be an enum");
int added = (int)(object)e | (int)(object)flag;
e = (T)(object)added;
return e;
}
对
internal static class EnumExtensions
{
public static bool IsDefinedAndNotDefault<T>(this T value)
where T : Enum
{
return Enum.IsDefined(typeof(T), value) && !value.Equals(default(T));
}
}