Присвойте несколько значений элементам перечисления

Привет, у меня есть это перечисление в настоящее время

[Serializable]
public enum Country
{
    US      = 1,
    Canada  = 2,
}

Когда я обычно получаю целое число из базы данных, я конвертирую его в перечисление, используя

(Country) Convert.ToInt32("1")

Теперь у меня есть 2 субрегиона в США и Канаде, 1 и 2 для США и 3 и 4 для Канады. Поэтому, когда я делаю

(Country) Convert.ToInt32("1") или (Country) Convert.ToInt32("2") я должен получить перечисление для США. и для 3 и 4 Канада. Как мне это реализовать?

[Serializable]
public enum Country
{
    US      = 1,2
    Canada  = 3,4
}

Что-то вроде этого. Это, вероятно, неправильно, но просто дать вам Идею.


person tHeSiD    schedule 21.12.2010    source источник


Ответы (8)


Конструкция enum может не подходить для моделирования такого рода проблем.

Я бы предложил создать класс для представления информации о стране и предоставить методы преобразования в числовые представления и обратно. При подобных проблемах вам также необходимо решить, какое кодовое значение вы будете использовать при преобразовании выбранного экземпляра Country в числовое значение.

Шаблон Enum Object может быть полезной отправной точкой для моделирования такой ситуации:

public sealed class Country
{
    // initialize appropriately in the constructor...
    private readonly int[] m_Values;
    private readonly string m_Name;

    // make the constructor private so that only this class can set up instances
    private Country( string name, int[] codes ) { ... }

    public static Country US = new Country("United States", new[]{ 1,2 } );
    public static Country Canada = new Country("Canada", new[] {3,4} );

    public static Country FromCode( int code ) { ... }
    public override string ToString() { return m_Name; }
    // ... etc...
}

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

person LBushkin    schedule 21.12.2010
comment
Спасибо за идею, я реализую ее в другой ситуации в том же проекте. Менять существующий действительно больно, поэтому я прикрепил быстрое исправление. Но это намного лучше. - person tHeSiD; 22.12.2010

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

[Serializable]
[Flags]
public enum Country
{
    US      = 1,
    Canada  = 2,
    Northern = 4,
    Southern = 8
}

Вы можете сделать это: Countries = Country.US | Country.Northern. Если нет, вам нужно найти другой способ, возможно, другое свойство или, что еще лучше, класс Location.

person Femaref    schedule 21.12.2010

Вам нужно будет сделать что-то вроде этого:

class Region
{
    static readonly RegionMap = new Dictionary<int,string>
    {
        { 1, "US" },
        { 2, "US" },
        { 3, "Canada" }
        { 4, "Canada" }
    }

    public static string GetRegion(int code)
    {
        string name;
        if (!RegionMap.TryGetValue(code, out name)
        {
            // Error handling here
        }
        return name;
    }
}

Затем найдите строку на основе значения из базы данных:

string region = Region.GetRegion(dbVal);
person Andrew Hare    schedule 21.12.2010
comment
Я нашел это в поисках чего-то другого. Это самый разумный ответ для меня. Конечно, этот вопрос был задан 5½ лет назад! - person MarkMYoung; 19.04.2016

Может быть, что-то вроде этого?

static Country ConvertRegionToCountry(string region)
{
    switch (region)
    {
        case "1":
        case "2":
            return Country.US;

        case "3":
        case "4":
            return Country.Canada;
    }
}
person dtb    schedule 21.12.2010

Ах, я просто использовал функцию вместо прямого приведения типов. Гораздо проще, чем реализовать что-то совершенно другое. У меня уже есть много кода, работающего на этом, поэтому я не могу его сильно изменить, но вот что я сделал.

public Country GetCountryByTaxID(int taxID)
        {
            if (taxID == 3 || taxID == 4)
            {
                return Country.USA;
            }
            else 
            {
                return Country.Canada;
            }
        }  
person tHeSiD    schedule 21.12.2010

Для меня это похоже на проблему набора, где 1 и 2 находятся в наборе США, а 3 и 4 - в наборе Канада. В проекте кода есть определенный код, который, как мне кажется, лучше моделирует проблему.

person rerun    schedule 21.12.2010

В дополнение к ответу dtb (и тем эквивалентным предложениям if) я только что реализовал «переопределенную» версию System.Convert в пространстве имен моего приложения:

public static class Convert
{
    public static object ChangeType
        (object value, Type conversionType, IFormatProvider provider)
    {
        int country;
        if (conversionType == typeof(Country)
            && int.TryParse(value.ToString(), out country))
        {
            switch (country)
            {
                case 1:
                case 2:
                    return Country.US;
                case 3:
                case 4:
                    return Country.Canada;
            }
        }

        // For most cases, including any country unmatched above...
        return System.Convert.ChangeType(value, conversionType, provider);
    }
}

Исходные методы класса Convert mscorlib.dll теперь, конечно же, должны иметь префикс "System.", так что любые уточнения приветствуются!

person mosi    schedule 21.08.2013

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

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

  • 2 байта как ushort (0x1234 как 0x12 и 0x34)
  • 2 ushorts как uint32 (0x12345678 как 0x1234 и 0x5678)
  • 2 единицы как улонг (0x0123456789ABCDEF как 0x01234567 и 0x89ABCDEF)
  • 8 байт в виде улонга (надеюсь, вы меня поняли)

и так далее.

Пример:

public enum CompoundEnum: ushort
{
    MenuOneOne = 0x101, // Can be split into bytes 0x1 and 0x1
    MenuOneTwo = 0x102, // Can be split into bytes 0x1 and 0x2
    MenuTwoOne = 0x201, // Can be split into bytes 0x2 and 0x1
}

Я не очень хорошо разбираюсь в том, как отрицательные значения хранятся в разных системах, но я предполагаю, что любой, у кого достаточно знаний о хранении отрицаний, также может легко «составить» значения со знаком. Кроме того, лично я предпочитаю представление в шестнадцатеричном формате, поскольку таким образом легче визуально читать отдельные значения.

Там достаточно о том, как вычислять значения с помощью сдвига битов (по крайней мере, я надеюсь, что это называется смещением битов), поэтому я просто свяжу этот ответ здесь: https://stackoverflow.com/a/3099367/1543356

person RiA    schedule 18.12.2020