Using an enum as an array index in C#

前端 未结 10 941
死守一世寂寞
死守一世寂寞 2020-12-28 14:17

I want to do the same as in this question, that is:

enum DaysOfTheWeek {Sunday=0, Monday, Tuesday...};
string[] message_array = new string[number_of_items_at         


        
10条回答
  •  既然无缘
    2020-12-28 14:32

    It was a very good answer by @ian-goldby, but it didn't address the issue raised by @zar-shardan, which is an issue I hit myself. Below is my take on a solution, with a an extension class for converting an IEnumerable, and a test class below that:

    /// 
    /// An array indexed by an enumerated type instead of an integer
    /// 
    public class ArrayIndexedByEnum : IEnumerable where TKey : Enum
    {
      private readonly Array _array;
      private readonly Dictionary _dictionary;
    
      /// 
      /// Creates the initial array, populated with the defaults for TElement
      /// 
      public ArrayIndexedByEnum()
      {
        var min = Convert.ToInt64(Enum.GetValues(typeof(TKey)).Cast().Min());
        var max = Convert.ToInt64(Enum.GetValues(typeof(TKey)).Cast().Max());
        var size = max - min + 1;
    
        // Check that we aren't creating a ridiculously big array, if we are,
        // then use a dictionary instead
        if (min >= Int32.MinValue && 
            max <= Int32.MaxValue && 
            size < Enum.GetValues(typeof(TKey)).Length * 3L)
        {
          var lowerBound = Convert.ToInt32(min);
          var upperBound = Convert.ToInt32(max);
          _array = Array.CreateInstance(typeof(TElement), new int[] {(int)size }, new int[] { lowerBound });
        }
        else
        {
          _dictionary = new Dictionary();
          foreach (var value in Enum.GetValues(typeof(TKey)).Cast())
          {
            _dictionary[value] = default(TElement);
          }
        }
      }
    
      /// 
      /// Gets the element by enumerated type
      /// 
      public TElement this[TKey key]
      {
        get => (TElement)(_array?.GetValue(Convert.ToInt32(key)) ?? _dictionary[key]);
        set
        {
          if (_array != null)
          {
            _array.SetValue(value, Convert.ToInt32(key));
          }
          else
          {
            _dictionary[key] = value;
          }
        }
      }
    
      /// 
      /// Gets a generic enumerator
      /// 
      public IEnumerator GetEnumerator()
      {
        return Enum.GetValues(typeof(TKey)).Cast().Select(k => this[k]).GetEnumerator();
      }
    
      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
      {
        return GetEnumerator();
      }
    }
    

    Here's the extension class:

    /// 
    /// Extensions for converting IEnumerable to ArrayIndexedByEnum
    /// 
    public static class ArrayIndexedByEnumExtensions
    {
      /// 
      /// Creates a ArrayIndexedByEnumExtensions from an System.Collections.Generic.IEnumerable
      /// according to specified key selector and element selector functions.
      /// 
      public static ArrayIndexedByEnum ToArrayIndexedByEnum(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : Enum
      {
        var array = new ArrayIndexedByEnum();
        foreach(var item in source)
        {
          array[keySelector(item)] = elementSelector(item);
        }
        return array;
      }
      /// 
      /// Creates a ArrayIndexedByEnum from an System.Collections.Generic.IEnumerable
      /// according to a specified key selector function.
      /// 
      public static ArrayIndexedByEnum ToArrayIndexedByEnum(this IEnumerable source, Func keySelector) where TKey : Enum
      {
        return source.ToArrayIndexedByEnum(keySelector, i => i);
      }
    }
    

    And here are my tests:

    [TestClass]
    public class ArrayIndexedByEnumUnitTest
    {
      private enum OddNumbersEnum : UInt16
      {
        One = 1,
        Three = 3,
        Five = 5,
        Seven = 7,
        Nine = 9
      }
    
      private enum PowersOf2 : Int64
      {
        TwoP0 = 1,
        TwoP1 = 2,
        TwoP2 = 4,
        TwoP3 = 8,
        TwoP4 = 16,
        TwoP5 = 32,
        TwoP6 = 64,
        TwoP7 = 128,
        TwoP8 = 256,
        TwoP9 = 512,
        TwoP10 = 1_024,
        TwoP11 = 2_048,
        TwoP12 = 4_096,
        TwoP13 = 8_192,
        TwoP14 = 16_384,
        TwoP15 = 32_768,
        TwoP16 = 65_536,
        TwoP17 = 131_072,
        TwoP18 = 262_144,
        TwoP19 = 524_288,
        TwoP20 = 1_048_576,
        TwoP21 = 2_097_152,
        TwoP22 = 4_194_304,
        TwoP23 = 8_388_608,
        TwoP24 = 16_777_216,
        TwoP25 = 33_554_432,
        TwoP26 = 67_108_864,
        TwoP27 = 134_217_728,
        TwoP28 = 268_435_456,
        TwoP29 = 536_870_912,
        TwoP30 = 1_073_741_824,
        TwoP31 = 2_147_483_648,
        TwoP32 = 4_294_967_296,
        TwoP33 = 8_589_934_592,
        TwoP34 = 17_179_869_184,
        TwoP35 = 34_359_738_368,
        TwoP36 = 68_719_476_736,
        TwoP37 = 137_438_953_472,
        TwoP38 = 274_877_906_944,
        TwoP39 = 549_755_813_888,
        TwoP40 = 1_099_511_627_776,
        TwoP41 = 2_199_023_255_552,
        TwoP42 = 4_398_046_511_104,
        TwoP43 = 8_796_093_022_208,
        TwoP44 = 17_592_186_044_416,
        TwoP45 = 35_184_372_088_832,
        TwoP46 = 70_368_744_177_664,
        TwoP47 = 140_737_488_355_328,
        TwoP48 = 281_474_976_710_656,
        TwoP49 = 562_949_953_421_312,
        TwoP50 = 1_125_899_906_842_620,
        TwoP51 = 2_251_799_813_685_250,
        TwoP52 = 4_503_599_627_370_500,
        TwoP53 = 9_007_199_254_740_990,
        TwoP54 = 18_014_398_509_482_000,
        TwoP55 = 36_028_797_018_964_000,
        TwoP56 = 72_057_594_037_927_900,
        TwoP57 = 144_115_188_075_856_000,
        TwoP58 = 288_230_376_151_712_000,
        TwoP59 = 576_460_752_303_423_000,
        TwoP60 = 1_152_921_504_606_850_000,
      }
    
      [TestMethod]
      public void TestSimpleArray()
      {
        var array = new ArrayIndexedByEnum();
    
        var odds = Enum.GetValues(typeof(OddNumbersEnum)).Cast().ToList();
    
        // Store all the values
        foreach (var odd in odds)
        {
          array[odd] = odd.ToString();
        }
    
        // Check the retrieved values are the same as what was stored
        foreach (var odd in odds)
        {
          Assert.AreEqual(odd.ToString(), array[odd]);
        }
      }
    
      [TestMethod]
      public void TestPossiblyHugeArray()
      {
        var array = new ArrayIndexedByEnum();
    
        var powersOf2s = Enum.GetValues(typeof(PowersOf2)).Cast().ToList();
    
        // Store all the values
        foreach (var powerOf2 in powersOf2s)
        {
          array[powerOf2] = powerOf2.ToString();
        }
    
        // Check the retrieved values are the same as what was stored
        foreach (var powerOf2 in powersOf2s)
        {
          Assert.AreEqual(powerOf2.ToString(), array[powerOf2]);
        }
      }
    }
    

提交回复
热议问题