действительно ли диапазоны возможны с перечислениями?

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

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 является TextBook

8
задан John Saunders 22 July 2013 в 12:25
поделиться

7 ответов

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

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

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

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

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

8
ответ дан 3 November 2019 в 13:35
поделиться

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

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

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);
3
ответ дан 3 November 2019 в 13:35
поделиться

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

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
ответ дан 3 November 2019 в 13:35
поделиться

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

В 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# это позволяет, то это должно быть нормально", но это было бы полным безумием).

0
ответ дан 3 November 2019 в 13:35
поделиться

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

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

  • это требует некоторой модификации значения при приведении к 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 для журналов и т.д.

2
ответ дан 3 November 2019 в 13:35
поделиться

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

[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
}
11
ответ дан 3 November 2019 в 13:35
поделиться

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

1
ответ дан 3 November 2019 в 13:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: