【问题标题】:Best hybrid approach to a multi-dimensional array with strong typed indexing具有强类型索引的多维数组的最佳混合方法
【发布时间】:2009-02-21 23:07:37
【问题描述】:

我有一个多维数组。

int[][][] MyValues;

我想要的是通过强类型等效项(例如枚举)访问索引。我知道您可以从 Enum 类型中获取枚举值,但我的口味有点啰嗦。

我宁愿有办法强输入索引。

例如:

int CarNumber = MyValues[Racetrack.Daytona][Race.Daytona500][Driver.JGordon];

由于它类似于枚举,这将防止抛出任何越界异常,而且它为所有索引赋予了人类可读的良好含义。

我已经使用字典方法实现了这一点,但它似乎有点笨拙:

Dictionary<Racetrack,Dictionary<Race,<Dictionary<Driver,int>>> =
    new Dictionary<Racetrack,Dictionary<Race,<Dictionary<Driver,int>>>();

然后我可以通过枚举访问它,但我不太喜欢这种方法。看起来很“丑”。

我正在寻找一些替代方法来表示本质上是一个多维数组,同时使用人类可读的索引器,同时保持类型安全(例如,不能意外地使用驱动程序进行比赛,所以简单地使用 consts 不是一个好方法)。

有什么建议吗?

这将是一个编译时数组(上面的例子不是真实的,只是一个说明)所以我不必担心数组的插入或删除或其他操作。它将在值、大小和布局上保持不变。

使用带有 const 值的静态类也不是一个好方法,因为它并不强制只能将定义的值集作为索引器传递。

【问题讨论】:

    标签: c# data-structures collections


    【解决方案1】:

    听起来你想使用indexers 而不是数组。假设以下枚举(基于公式 1!):

    public enum Track
    {
        Spielberg,
        Adelaide,
        Casablanca,
        Liverpool,
        Melbourne,
        Berlin,
        Sakhir,
    }
    
    public enum Constructor
    {
        BMW,
        Ferrari,
        McLaren,
        Toyota,
        Williams
    }
    
    public enum Driver
    {
        Hamilton,
        Kovalainen,
        Raikkonen,
        Nakajima,
        Glock
    }
    

    基本结构如下:

    public class Race
    {
        int Year { get; set; }
        Track Track { get; set; }
        Driver[] Placings { get; set; }
        public int this[Driver driver] { } // placing by driver
    }
    
    public class Results
    {
        YearResults this[int index] { }
        DriverResults this[Driver index] { }
        TrackResults this[Track index] { }
        ConstructorResults this[Constructor index] { }
    }
    
    public class YearResults
    {
        YearDriverResults this[Driver index] { }
    }
    

    这当然是部分实现,但您可以通过这种方式使用索引器做一些非常酷的事情。就像您可以以任何顺序(假设您设置了所有中间类)使用任何值组合访问您的信息。

    它比多维数组或元组键字典更冗长,但我认为会给你更优雅的代码。

    【讨论】:

    • 这是一个很好的观点。有时我们会陷入将问题视为锤子解决方案的想法,我们忘记了它可能不是钉子。也许是螺丝或胶水。
    • 嗯,不,我不需要具有各种属性或方法的 Racetrack 或 Race 对象。它只是一个有约束的数字集合。但就像我说的,我并没有真正考虑过将它们定义为自己的类。
    【解决方案2】:

    Dictionary 中使用三重&lt;Racetrack,Race,Driver&gt; 作为键(定义您自己的类)怎么样?

    如果您确实需要使用数组,我认为您最好将其包装在自定义类中,该类只允许使用 RacetrackRaceDriver 枚举进行访问。

    【讨论】:

      【解决方案3】:

      很明显的问题.. List&lt;T&gt; 不适合你吗?

      【讨论】:

      • List 不允许您将枚举用作索引器而不进行强制转换或编写大量访问器来获取实际值,并且不是类型安全的。所以没有。
      • 我认为 List 是类型安全的?我想我很困惑。
      • 它的价值是安全的,而不是索引器。
      【解决方案4】:

      枚举是否相当小,值为 0...n?如果是这样,您可以使用多维数组但公开索引器。请注意,下面的代码使用矩形数组而不是锯齿状数组,但您可以很容易地对其进行调整。

      // In a static class somewhere. Just a convenience method to check
      // whether a value is defined or not. See comment in indexer.
      public static void CheckDefined<T>(this T value, String name)
          where T : struct
      {
          if (!Enum.IsDefined(typeof(T), value))
          {
              throw new ArgumentOutOfRangeException(name);
          }
      }
      
      
      // Somewhere else...
      private static int GetLength<T>() where T : struct
      {
          return Enum.GetValues(typeof(T)).Length;
      }
      
      private int[,,] array = new int[GetLength<Racetrack>(), 
                                      GetLength<Race>(),
                                      GetLength<Driver>()];
      
      public int this Car[Racetrack racetrack, Race race, Driver driver]
      {
        get
        {
          // If you don't care about just getting an
          // IndexOutOfRangeException, you could skip these three lines.
          racetrack.CheckDefined("racetrack");
          race.CheckDefined("race");
          driver.CheckDefined("driver");
          return array[(int) racetrack, (int) race, (int) driver);
        }
      }
      

      【讨论】:

      【解决方案5】:

      我不认为字典方法不好,但它并不优雅。如果你为你的字典创建了一个别名,事情会更好看:

      using RaceSetup = Dictionary<Racetrack,Dictionary<Race,<Dictionary<Driver,int>>>;
      

      或者您可以创建一个从字典派生的类:

      class RaceSetup : Dictionary<Racetrack,Dictionary<Race,<Dictionary<Driver,int>>>
      {}
      

      【讨论】:

      • 字典方法的更大问题是它创建了混乱的初始化代码。不是一个大问题,但仍然很丑。
      猜你喜欢
      • 1970-01-01
      • 2015-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多