title: More efficent ways of cleanly dealing with a multi-dimensional array keyd by enums
body: <p>I have a situation where I need to do many gets/sets, after perfomance analysis this is one of the more expensive parts of my application. Origionally I was using a Dictionary but switched to a jagged array internally which gave it a signficant perfomance boost, still I'd like to see if theres a way to improve the perfomance of this code without ditching the nice and useable syntax.</p>
  
  <p>Note calling Convert.ToInt32 is signficantly more expensive than calling a cast, and since the generic constraint TStatus : int doesn't work for an enum I had to implement this as a abstract class, it would be nice if this collection would work with any enum out of the box.</p>
  
  <p>Also I tried implementing yield for the IEnumerable, however that was actually slower than just populating a list.</p>
  
  <pre><code>    public abstract class LoanStatusVectorOverTime&lt;TStatus&gt; : ILoanStatusVectorOverTime&lt;TStatus&gt;
      where TStatus: struct
  {
      protected static readonly TStatus[] LoanStatusTypes = (TStatus[])Enum.GetValues(typeof(TStatus));
      protected static readonly int LoanStatusCount = Enum.GetValues(typeof(TStatus)).Length;
      protected const int MonthsSinceEventCount = 25;
  
      private readonly object SYNC = new object();
      protected double[,] VectorDictionary { get; set; }
      public LoanStatusVectorOverTime()
      {
          this.VectorDictionary = new double[LoanStatusCount, MonthsSinceEventCount];
      }
      public double this[TStatus status, int monthsSince]
      {
          get
          {
              if (monthsSince &gt;= MonthsSinceEventCount)
                  return 0;
              return VectorDictionary[GetKeyValue(status), monthsSince];
          }
          set
          {
              if (monthsSince &gt;= MonthsSinceEventCount)
                  return;
              VectorDictionary[GetKeyValue(status), monthsSince] = value;
          }
      }
      public double SumOverStatus(TStatus status)
      {
          double sum = 0;
          foreach (var fromStatus in LoanStatusTypes)
          {
              int i = 0;
              while (i &lt; MonthsSinceEventCount)
              {
                  sum += VectorDictionary[GetKeyValue(fromStatus), i];
                  i++;
              }
          }
          return sum;
      }
      public IEnumerator&lt;KeyValuePair&lt;Tuple&lt;TStatus, int&gt;, double&gt;&gt; GetEnumerator()
      {
          List&lt;KeyValuePair&lt;Tuple&lt;TStatus, int&gt;, double&gt;&gt; data = new List&lt;KeyValuePair&lt;Tuple&lt;TStatus, int&gt;, double&gt;&gt;();
          foreach (var fromStatus in LoanStatusTypes)
          {
              int i = 0;
              while (i &lt; MonthsSinceEventCount)
              {
                  var val = VectorDictionary[GetKeyValue(fromStatus), i];
                  if (val != default(double))
                      data.Add(new KeyValuePair&lt;Tuple&lt;TStatus, int&gt;, double&gt;(new Tuple&lt;TStatus, int&gt;(fromStatus, i), val));
                  i++;
              }
          }
          return data.GetEnumerator();
      }
      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
      {
          return GetEnumerator();
      }
      protected abstract int GetKeyValue(TStatus status);
      protected abstract ILoanStatusVectorOverTime&lt;TStatus&gt; Initalize();
      public ILoanStatusVectorOverTime&lt;TStatus&gt; Copy()
      {
          var vect = Initalize();
          foreach (var fromStatus in LoanStatusTypes)
          {
              int i = 0;
              while (i &lt; MonthsSinceEventCount)
              {
                  vect[fromStatus, i] = VectorDictionary[GetKeyValue(fromStatus), i];
                  i++;
              }
          }
          return vect;
      }
      public double SumOverAll(int monthsSince = 1)
      {
          double sum = 0;
          foreach (var status in LoanStatusTypes)
          {
              sum += this[status, monthsSince];
          }
          return sum;
      }
  }
      public class AssetResolutionVector : LoanStatusVectorOverTime&lt;AssetResolutionStatus&gt;
  {
      protected override int GetKeyValue(AssetResolutionStatus status)
      {
          return (int)status;
      }
  
      protected override ILoanStatusVectorOverTime&lt;AssetResolutionStatus&gt; Initalize()
      {
          return new AssetResolutionVector();
      }
  }
      var arvector = new AssetResolutionVector();
      arvector[AssetResolutionStatus.ShortSale, 1] = 10;
  </code></pre>