возможны ли диапазоны с перечислениями? - PullRequest
8 голосов
/ 06 мая 2010

В C # вы можете использовать числовые диапазоны в типах enum, например

public enum BookType
{
    Novel = 1,
    Journal = 2,
    Reference = 3,
    TextBook = 4 .. 10
}

РЕДАКТИРОВАТЬ: Причина, по которой это необходимо, заключается в приведении числа к типу перечисления, например:

int iBook = 5
BookType btBook = (BookType)ibook
Debug.Print "Book " + ibook + " is a " btBook

и ожидаемый результат: Книга 5 - это учебник

Ответы [ 9 ]

11 голосов
/ 06 мая 2010

Как говорили другие, нет, это невозможно. Можно комбинировать значения перечисления, если они являются флагами:

[Flags]
public enum BookType
{
    Novel = 0,
    Journal = 1 << 0,
    Reference = 1 << 1,
    TextBook1 = 1 << 2,
    TextBook2 = 1 << 3,
    TextBook3 = 1 << 4,
    TextBook4 = 1 << 5,
    TextBook5 = 1 << 6,
    TextBooks1To5 = TextBook1 | TextBook2 | TextBook3 | TextBook4 | TextBook5
}
8 голосов
/ 06 мая 2010

В соответствии со стандартом C # (p612, Язык программирования C #) значение, присваиваемое перечислению, должно быть постоянным целым числом (или любым подобным типом - long, byte, sbyte, short и т.д.), поэтому диапазон значений не действителен.

Мой компилятор (VS2008) согласен со спецификацией.

Поскольку вы не можете повторять имена в перечислении, самое близкое, что вы получите, будет что-то вроде этого:

public enum BookType
{
    Novel = 1,
    Journal = 2,
    Reference = 3,
    TextBook4 = 4,
    TextBook5 = 5, ...
    TextBook10 = 10
}

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

4 голосов
/ 12 сентября 2012

Поскольку вы не можете назначить диапазон значений для перечисления, я подумал об альтернативном подходе для назначения перечисления в качестве предельного значения (пример основан на времени):

    private enum eTiming
    {
        eOnTime = 0,
        eSlightDelay = 5,
        eMinorDelay = 15,
        eDelayed = 30,
        eMajorDelay = 45,
        eSevereDelay = 60
    }

    private static eTiming CheckIfTimeDelayed(TimeSpan tsTime)
    {
        eTiming etiming = eTiming.eOnTime;

        foreach (eTiming eT in Enum.GetValues(typeof(eTiming)))
        {
            if (Convert.ToInt16(eT) <= tsTime.TotalMinutes)
                etiming = eT;
        }

        return etiming;
    }

Предполагается, что перечисление отсортировано и неожиданно работает со значениями со знаком (-).

3 голосов
/ 06 мая 2010

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

например. что-то похожее на это решит вашу проблему:

public sealed class BookType
{
    public static readonly BookType Novel = new BookType(1, 1, "Novel");
    public static readonly BookType Journal = new BookType(2, 2, "Journal");
    public static readonly BookType Reference = new BookType(3, 3, "Reference");
    public static readonly BookType Textbook = new BookType(4, 10, "Textbook");

    public int Low { get; private set; }
    public int High { get; private set; }
    private string name;

    private static class BookTypeLookup
    {
        public static readonly Dictionary<int, BookType> lookup = new Dictionary<int, BookType>();
    }

    private BookType(int low, int high, string name)
    {

        this.Low = low;
        this.High = high;
        this.name = name;

        for (int i = low; i <= high; i++)
            BookTypeLookup.lookup.Add(i, this);
    }

    public override string ToString()
    {
        return name;
    }

    public static implicit operator BookType(int value)
    {
        BookType result = null;
        if (BookTypeLookup.lookup.TryGetValue(value, out result))
            return result;

        throw new ArgumentOutOfRangeException("BookType not found");
    }
}

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

, например

 var bookType = (BookType)5;
 Console.WriteLine(bookType);
2 голосов
/ 06 мая 2010

Если вы можете присваивать значения перечисляемым строкам самостоятельно, вы можете использовать некоторую битмагию для сопоставления нескольких значений int с одним и тем же значением перечисления. Подтипы могут быть сами по себе для каждого BookType (NovelTypes, JournalTypes и т. Д.).

С другой стороны

  • это требует некоторой модификации значения при приведении к BookType
  • каждый диапазон подтипов имеет одинаковый размер (16 в текущем примере.
  • это немного менее читабельно, чем простой Novel = 3 вид отображения.

Пример кода:

class Program
{
    /// <summary> Number of subtypes reserved for each BookType. </summary>
    private const byte BookTypeStep = 16;
    /// <summary> Bitmask to use to extract BookType from a byte. </summary>
    private const byte BookTypeExtractor = Byte.MaxValue - BookTypeStep + 1;
    /// <summary> Bitmask to use to extract Book subtype from a byte. </summary>
    private const byte BookSubTypeExtractor = BookTypeStep -1;

    public enum BookType : byte
    {
        Unknown = 0,
        Novel = BookTypeStep * 1,
        Journal = BookTypeStep * 2,
        Reference = BookTypeStep * 3,
        TextBook = BookTypeStep * 4,
    }

    static void Main(string[] args)
    {
        for(int i = 16; i < 80; i++)
        {
            Console.WriteLine("{0}\tof type {1} ({2}),\tsubtype nr {3}",
                i,
                i & BookTypeExtractor,
                (BookType)(i & BookTypeExtractor),
                i & BookSubTypeExtractor
            );
        }
        Console.ReadLine();
    }
}

Этот пример имеет диапазоны 16-31 для романов, 32-47 для журналов и т. Д.

1 голос
/ 06 мая 2010

Вы можете выбрать словарь.

var BookType = new Dictionary<int, string>();
BookType.Add(1, "Novel");
BookType.Add(2, "Journal");
BookType.Add(3, "Reference");
BookType.Add(4, "TextBook");
BookType.Add(5, "TextBook");
BookType.Add(6, "TextBook");
BookType.Add(7, "TextBook");
BookType.Add(8, "TextBook");
BookType.Add(9, "TextBook");
BookType.Add(10, "TextBook");

int iBook = 5 
Debug.Print "Book " + iBook + " is a " BookType[iBook]

Редактировать : Вы также можете объявить свой словарь только для чтения, если он находится на уровне класса.

Вы можете использовать перечисление в качестве значения словаря вместо строки.

1 голос
/ 06 мая 2010

Нет, это не так. Если числовые константы, которые вы пытаетесь отобразить, имеют истинное значение, вам все равно потребуется отдельный член для каждой числовой константы. Как TextBook4, TextBook5 и т. Д.

0 голосов
/ 23 июля 2013

Самый простой ответ на ваш вопрос - Нет. Самый простой способ выполнить то, что вы хотите:

public enum BookType
{
    Novel = 1,
    Journal = 2,
    Reference = 3,
    TextBook = 4
}

public void bookOutput(int book)
{
   if(book < 4)
       Console.Writeline("Book "+book+" is a " + ((BookType)book).ToString());
   else
       Console.Writeline("Book "+book+" is a " + BookType.TextBook.ToString());
}

Идея состоит в том, чтобы позволить enum быть отдельными значениями и обрабатывать диапазон с помощью логических операторов.

0 голосов
/ 06 мая 2010

Возможно, вы хотели задать связанный вопрос: может ли у вас быть более одного перечисления (не уверен, что у меня правильная терминология, но мой пример покажет, что я имею в виду) для каждого значения?

В C # вы можете сделать что-то вроде этого:

public enum BookType
{
    Novel = 1,
    Journal = 2,
    Magazine = 2,
    Reference = 3,
    TextBook = 4,
    LabWorkbook = 4,
    Dictionary = 5,
    Encyclopedia = 5
}

Таким образом, вы можете использовать либо BookType.Journal, либо BookType.Magazine в своем коде, любое из которых является синонимом значения 2. Должно ли это быть выполнено, это другой вопрос - я не знаком с аргументами за или против этого (я хотел бы сказать, «если C # позволяет это, это должно быть ОК», но это было бы совершенно безумно).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...