Лучший гибридный подход к многомерному массиву с сильной типизированной индексацией


4

У меня есть то, что составляет многомерный массив.

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 не является хорошим подходом).

Любые предложения?

Это будет массив времени компиляции (пример выше не является реальным, просто иллюстрацией), поэтому мне не нужно беспокоиться о вставках или удалении или других манипуляциях с массивом. Он останется неизменным, как по величине, так и по размеру.

Использование статического класса с константными значениями также не является хорошим подходом, поскольку оно не предусматривает, что только набор значений, определенных в качестве параметров, можно передавать в качестве индексаторов.

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] { } 
} 

Это, конечно, частичная реализация, но вы можете сделать некоторые довольно прохладно вещи с индексаторами таким образом. Как вы можете получить доступ к вашей информации с любой комбинацией значений в любом порядке (при условии, что вы настроили все промежуточные классы).

Его словарь, чем многомерный массив или словарь с корневым ключом, но я думаю, это даст вам гораздо более элегантный код.

  0

Это хороший момент. Иногда мы задумываемся над проблемой, как решение Hammer, которое мы забываем, возможно, это не гвоздь. Может быть, это винт или клей. 21 фев. 092009-02-21 23:25:56

  0

Ну, нет, мне не нужны объекты Racetrack или Race со всеми видами свойств или методов. Это просто набор чисел с ограничениями. Но, как я уже сказал, на самом деле я не определял их как свои классы. 21 фев. 092009-02-21 23:58:26


0

Очевидный вопрос .. Будет ли List<T> не работать для вас?

  0

Список <T> не позволяет использовать перечисление в качестве индексатора без бросков или написания большого количества аксессуаров для получения фактического значения и не является безопасным по типу. Так нет. 21 фев. 092009-02-21 23:12:14

  0

Я думал, что список <T> был типом сейфа? Наверное, я в замешательстве. 21 фев. 092009-02-21 23:14:01

  0

Это безопасно для его ценности, а не индексатора. 21 фев. 092009-02-21 23:14:44


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); 
    } 
} 
  0

Можете ли вы объяснить, что такое бит «public int this Car»? для чего это «это»? 21 фев. 092009-02-21 23:37:41

  0

Это объявление индексатора. См. Http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx 22 фев. 092009-02-22 09:08:14

  0

Да, узнайте что-то новое каждый день. Благодарю. 22 фев. 092009-02-22 11:36:03


2

Как об использовании тройной <Racetrack,Race,Driver> в качестве ключа (определить свой собственный класс) в Dictionary?

Если вам действительно нужно использовать массив, я не думаю, что вы можете сделать лучше, чем обернув его в пользовательский класс, который позволяет получить доступ только с помощью Racetrack, Race, Driver перечислений.


0

Я не думаю, что подход к словарю плох, но он не изящный. Если вы создали псевдоним для словаря словарных вещей будет выглядеть лучше:

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

Или вы могли бы создать класс, производный из словаря:

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

Большая проблема со словарным подходом заключается в том, что он создает беспорядочный код инициализации. Не огромная проблема, но все же уродливая. 22 фев. 092009-02-22 00:00:45