具有强类型索引的多维数组的最佳混合方法

时间:2009-02-21 23:07:37

标签: c# data-structures collections

我有多维数组。

int[][][] MyValues;

我想要的是通过强类型的equivelent访问索引,例如枚举。我知道你可以从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>>>();

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

我正在寻找一些替代方法,在使用人类可读索引器的同时表示基本上是多维数组,同时保持类型安全性(例如,不能无意中使用Race作为Race)简单地使用consts不是一个好方法。

有什么建议吗?

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

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

5 个答案:

答案 0 :(得分:5)

听起来我想要使用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] { }
}

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

它比一个多维数组或一个元组键控词典更有语言,但我认为它会给你更优雅的代码。

答案 1 :(得分:2)

如何在<Racetrack,Race,Driver>中使用三Dictionary作为键(定义自己的类)?

如果你真的需要使用数组,我认为你不能把它包装在一个自定义类中,只允许使用RacetrackRaceDriver进行访问枚举。

答案 2 :(得分:0)

明显的问题.. List<T>不适合你吗?

答案 3 :(得分:0)

枚举是否相当小,值为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);
  }
}

答案 4 :(得分:0)

我不认为字典方法不好,但它不优雅。如果您为字典字典创建了别名,那么事情看起来会更好:

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

或者你可以创建一个派生自字典的类:

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