C#:Enum.IsDefined在组合标志上

我有这个枚举:

[Flags] public enum ExportFormat { None = 0, Csv = 1, Tsv = 2, Excel = 4, All = Excel | Csv | Tsv } 

我试图在这个(或任何,真的)枚举上做一个包装,它通知变化。 目前它看起来像这样:

 public class NotifyingEnum : INotifyPropertyChanged where T : struct { private T value; public event PropertyChangedEventHandler PropertyChanged; public NotifyingEnum() { if (!typeof (T).IsEnum) throw new ArgumentException("Type T must be an Enum"); } public T Value { get { return value; } set { if (!Enum.IsDefined(typeof (T), value)) throw new ArgumentOutOfRangeException("value", value, "Value not defined in enum, " + typeof (T).Name); if (!this.value.Equals(value)) { this.value = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs("Value")); } } } } 

由于枚举可以真正分配任何值,我想检查是否定义了给定的值。 但我发现了一个问题。 如果我在这里给它一个由例如Csv | Excel组成的枚举 Csv | Excel ,然后Enum.IsDefined将返回false 。 显然是因为我没有定义任何由这两个组成的枚举。 我想在某种程度上是合乎逻辑的,但我应该如何检查给定值是否有效? 换句话说,为了使它工作,我需要交换以下这一行?

 if (!Enum.IsDefined(typeof (T), value)) 

使用基于标志的枚举,它是关于设置与否。 因此,对于’ExportFormat’,如果设置了第1位,则它是CSV格式,即使可能设置了更多位。 第1位和第2位是否设置了无效值? 这是主观的:从作为一个组的值的角度来看,它是无效的(没有为第1和第2位设置定义的位模式)但是,因为每个值都是一个位,单独查看它们,它可能是位1和2设置的值有效。

如果传入值0011111011,那是否是有效值? 嗯,这取决于你在寻找什么:如果你正在查看整个值,那么它是一个无效的值,但如果你正在查看单个位,它是一个正确的值:它设置的位不是定义了,但没关系,因为基于标志的枚举是“按位”检查的:你没有将它们与一个值进行比较,而是检查是否设置了一个位。

因此,由于您的逻辑将检查设置哪些位来选择要选择的格式,因此无需检查枚举值是否已定义:您有3种格式:如果设置了相应格式的位,则格式为选择。 那是你应该写的逻辑。

我们知道转换为字符串的枚举值永远不会以数字开头,但总是会有一个无效值的数字。 这是最简单的解决方案:

 public static bool IsDefinedEx(this Enum yourEnum) { char firstDigit = yourEnum.ToString()[0]; if (Char.IsDigit(firstDigit) || firstDigit == '-') // Account for signed enums too.. return false; return true; } 

使用该扩展方法而不是库存IsDefined,这应该可以解决您的问题。

我将在位级操作并检查新值中设置的所有位是否都在All值中设置:

 if ( ! (All & NewValue) == NewValue ) 

您必须亲自了解自己如何做到这一点,也许您需要将所有值转换为int然后执行按位比较。

也许尝试抓住解析?
你想要传递的价值观?

  public T Value { get { return value; } set { try { Enum.Parse(typeof(T), value.ToString()); } catch { throw new ArgumentOutOfRangeException("value", value, "Value not defined in enum, " + typeof(T).Name); } if (!this.value.Equals(value)) { this.value = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs("Value")); } } } 

我知道这个post在很长一段时间内都没有得到解答,但我认为使用内置函数回答它对于那些在我之后访问它的人来说是好事。

使用OP的原始枚举,您可以使用以下代码解析位掩码值。

  ExportFormat format; if (!Enum.TryParse(value.ToString(), out format)) { // Could not parse } 

希望有所帮助。

这是一种方法(使用Linq):

  private static bool IsDefined(long value) where T : struct { var max = Enum.GetValues(typeof(T)).Cast() .Select(v => Convert.ToInt64(v)). Aggregate((e1, e2) => e1 | e2); return (max & value) == value; } 

看到这里 。 相当多的代码。

这是一个很有效的小扩展方法。

 static void Main(string[] args) { var x = ExportFormat.Csv | ExportFormat.Excel; var y = ExportFormat.Csv | ExportFormat.Word; var z = (ExportFormat)16; //undefined value var xx = x.IsDefined(); //true var yy = y.IsDefined(); //false var zz = z.IsDefined(); //false } public static bool IsDefined(this Enum value) { if (value == null) return false; foreach (Enum item in Enum.GetValues(value.GetType())) if (item.HasFlag(value)) return true; return false; } [Flags] public enum ExportFormat { None = 0, Csv = 1, Tsv = 2, Excel = 4, Word = 8, All = Excel | Csv | Tsv } 

以下方法适用于按代码组合的项目,这些项目未分组在枚举中:

 static void Main(string[] args) { var x = ExportFormat.Csv | ExportFormat.Excel; var y = ExportFormat.Csv | ExportFormat.Word; var z = (ExportFormat)16; //undefined value var xx = x.IsDefined(); //true var yy = y.IsDefined(); //true var zz = z.IsDefined(); //false } public static bool IsDefined(this ExportFormat value) { var max = Enum.GetValues(typeof(ExportFormat)).Cast() .Aggregate((e1,e2) => e1 | e2); return (max & value) == value; } 

如果您使用的是支持DLR的C#4.0,您可以使用以下很酷的不可知扩展方法:

 public static bool IsDefined(this Enum value) { dynamic dyn = value; var max = Enum.GetValues(value.GetType()).Cast(). Aggregate((e1,e2) => e1 | e2); return (max & dyn) == dyn; } 

注意 – 必须这样做,因为:

  1. 运营商|&不能应用于EnumEnum类型的操作数
  2. 这些运算符在编译器中定义并且没有反映出来,因此无法使用reflection / Linq表达式检索它们,相信我 – 我已经尝试了所有…