【问题标题】:How to prevent duplicate values in enum?如何防止枚举中的重复值?
【发布时间】:2009-09-15 07:58:05
【问题描述】:

我想知道有没有办法防止带有重复键的enum 进行编译?

例如下面的enum 将编译

public enum EDuplicates
{
    Unique,
    Duplicate = 0,
    Keys = 1,
    Compilation = 1
}

虽然这段代码

Console.WriteLine(EDuplicates.Unique);
Console.WriteLine(EDuplicates.Duplicate);
Console.WriteLine(EDuplicates.Keys);
Console.WriteLine(EDuplicates.Compilation);

将打印

Duplicate
Duplicate
Keys
Keys

【问题讨论】:

标签: c# .net enums


【解决方案1】:

这是一个检查它的简单单元测试,应该会快一点:

[TestMethod]
public void Test()
{
  var enums = (myEnum[])Enum.GetValues(typeof(myEnum));
  Assert.IsTrue(enums.Count() == enums.Distinct().Count());
}

【讨论】:

    【解决方案2】:

    语言规范并未禁止这样做,因此任何符合 C# 的编译器都应该允许这样做。你总是可以调整 Mono 编译器来禁止它 - 但坦率地说,编写一个单元测试来扫描你的程序集以查找枚举并以这种方式执行它会更简单。

    【讨论】:

    • 我可能错过了这里的重点:支持这一点的有用场景是什么?如果没有有用的场景,为什么您更愿意为此编写单元测试而不是让编译器处理这种情况?
    • @Brian:避免破坏现有代码。向后兼容性很重要,符合规范也很重要。我无法立即想到任何有用的场景,但这并不意味着我想破坏任何已经在使用它的人。
    • @Brian:如果您出于某种原因希望在不破坏旧代码的情况下更改枚举值的名称,它会很有用:添加一个具有新名称和与旧代码相同数值的新值一、用Obsolete属性装饰旧值。
    • 我在为半自动生成的枚举编写单元测试时发现了这个问题(重复键)。这是一个令人不快的惊喜,所以我对是否有办法以某种方式确保这一点感兴趣。我在想一个属性或编译器标志或类似的东西。
    • 对于为同一事物提供多个替代名称也不会有用吗? (如“Ace”和“HighestFaceCard”)。还是那是一种反模式?
    【解决方案3】:

    检查枚举并显示哪些特定枚举值有重复项的单元测试:

    [Fact]
    public void MyEnumTest()
    {
        var values = (MyEnum[])Enum.GetValues(typeof(MyEnum));
        var duplicateValues = values.GroupBy(x => x).Where(g => g.Count() > 1).Select(g => g.Key).ToArray();
        Assert.True(duplicateValues.Length == 0, "MyEnum has duplicate values for: " + string.Join(", ", duplicateValues));
    }
    

    【讨论】:

    • 应该是 Assert.IsTrue.
    • [Fact] 和 Assert.True 用于 xUnit 测试框架。
    【解决方案4】:
    public bool ValidateAllDistinct(Type enumType)
    {
        return !Enum.GetNames(enumType).All(outerName
            => Enum.GetNames(enumType).Any(innerName
                => innerName == outerName 
                    ? true 
                    : Enum.Parse(enumType, innerName) != Enum.Parse(enumType, outerName)));
    }
    

    我为您的单元测试提供了简单的测试方法。

    【讨论】:

    • 这有点像我必须编写的单元测试,唯一的区别是打印重复的键。
    • 根据this fiddle 它不起作用。如果我遗漏了什么,请纠正我。
    【解决方案5】:

    另一种基于选定列具有唯一值的解决方案

    var uniqueData = temp.Select(u => new tblschClassSchedule
                {
                    TeacherName = u.TeacherName,
                    SubjectName = u.SubjectName,
    
                }).Distinct() ;
    

    这将只获得 2 列,并且这些列只有唯一数据

    【讨论】:

      【解决方案6】:

      另外,如果您想测试项目中的所有枚举:

         [Test]
          public void EnumsDoNotHaveDuplicates()
          {
              IEnumerable<Type> enums = typeof(MyEnum).Assembly
                  .GetTypes()
                  .Where(t => t.IsEnum && t.IsPublic);
      
              foreach (Type t in enums)
              {
                  MethodInfo method = typeof(EnumTestFixture).GetMethod(nameof(VerifyEnumHasNoDuplicates));
                  MethodInfo generic = method.MakeGenericMethod(t);
                  generic.Invoke(this, null);
              }
          }
      
          public void VerifyEnumHasNoDuplicates<T>()
          {
              T[] values = (T[])Enum.GetValues(typeof(T));
              Assert.IsTrue(values.Count() == values.Distinct().Count(), $"{typeof(T).Name} has duplicates!");
          }
      

      MyEnum 替换为应测试的程序集中的任何Type

      如果您不喜欢使用反射的方法,或者您更喜欢每个枚举进行测试(无论出于何种原因),您仍然可以使用通用方法:

      VerifyEnumHasNoDuplicates&lt;MyEnum&gt;()

      【讨论】:

        猜你喜欢
        • 2014-02-05
        • 2014-02-02
        • 2016-11-26
        • 1970-01-01
        • 2012-08-31
        • 2016-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多