преобразовать перечисление в другой тип перечисления - PullRequest
100 голосов
/ 30 ноября 2009

У меня есть перечисление, например, 'Gender' (Male =0 , Female =1), и у меня есть другое перечисление от службы, которая имеет свой собственный enmen Пол (Male =0 , Female =1, Unknown =2)

У меня вопрос, как я могу написать что-то быстрое и приятное для преобразования из их перечисления в мое?

Ответы [ 13 ]

179 голосов
/ 30 ноября 2009

Учитывая Enum1 value = ..., тогда если вы подразумеваете под именем:

Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());

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

Enum2 value2 = (Enum2)value;

(при приведении вы можете использовать Enum.IsDefined для проверки допустимых значений)

74 голосов
/ 30 ноября 2009

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

public static class TheirGenderExtensions
{
    public static MyGender ToMyGender(this TheirGender value)
    {
        // insert switch statement here
    }
}

public static class MyGenderExtensions
{
    public static TheirGender ToTheirGender(this MyGender value)
    {
        // insert switch statement here
    }
}

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

44 голосов
/ 30 ноября 2009

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

Gender2 gender2 = (Gender2)((int)gender1);
20 голосов
/ 30 ноября 2009

Чтобы быть точным, я обычно создаю пару функций, одна из которых принимает Enum 1 и возвращает Enum 2, а другая - Enum 2 и возвращает Enum 1. Каждая состоит из оператора case, отображающего входные данные в выходы, и регистр по умолчанию выдает исключение с сообщением, сообщающим о неожиданном значении.

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

14 голосов
/ 04 ноября 2015

Если у нас есть:

enum Gender
{
    M = 0,
    F = 1,
    U = 2
}

и

enum Gender2
{
    Male = 0,
    Female = 1,
    Unknown = 2
}

Смело можем сделать

var gender = Gender.M;
var gender2   = (Gender2)(int)gender;

Или даже

var enumOfGender2Type = (Gender2)0;

Если вы хотите охватить случай, когда перечисление справа от знака '=' имеет больше значений, чем перечисление слева - вам придется написать свой собственный метод / словарь, чтобы охватить это, как предлагали другие .

13 голосов
/ 02 февраля 2013

Вы можете написать простой общий метод расширения, подобный этому

public static T ConvertTo<T>(this object value)            
    where T : struct,IConvertible
{
    var sourceType = value.GetType();
    if (!sourceType.IsEnum)
        throw new ArgumentException("Source type is not enum");
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Destination type is not enum");
    return (T)Enum.Parse(typeof(T), value.ToString());
}
8 голосов
/ 30 ноября 2009

вы можете написать простую функцию, подобную следующей:

public static MyGender ConvertTo(TheirGender theirGender)
{
    switch(theirGender)
    {
        case TheirGender.Male:
            break;//return male
        case TheirGender.Female:
            break;//return female
        case TheirGender.Unknown:
            break;//return whatever
    }
}
6 голосов
/ 13 августа 2015

Вот версия метода расширения, если кому-то интересно

public static TEnum ConvertEnum<TEnum >(this Enum source)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true);
    }

// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();
2 голосов
/ 17 сентября 2018

Основываясь на ответе Джастина выше, я придумал это:

    /// <summary>
    /// Converts Enum Value to different Enum Value (by Value Name) See https://stackoverflow.com/a/31993512/6500501.
    /// </summary>
    /// <typeparam name="TEnum">The type of the enum to convert to.</typeparam>
    /// <param name="source">The source enum to convert from.</param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public static TEnum ConvertTo<TEnum>(this Enum source)
    {
        try
        {
            return (TEnum) Enum.Parse(typeof(TEnum), source.ToString(), ignoreCase: true);
        }
        catch (ArgumentException aex)
        {
            throw new InvalidOperationException
            (
                $"Could not convert {source.GetType().ToString()} [{source.ToString()}] to {typeof(TEnum).ToString()}", aex
            );
        }
    }
2 голосов
/ 16 мая 2014

Некоторое время назад я написал набор методов расширения, которые работают для нескольких различных типов Enum s. Один, в частности, работает для того, что вы пытаетесь выполнить, и обрабатывает Enum с FlagsAttribute, а также Enum с различными базовыми типами.

public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable
{
    if (typeCheck)
    {
        if (e.GetType() != flags.GetType())
            throw new ArgumentException("Argument is not the same type as this instance.", "flags");
    }

    var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum));

    var firstNum = Convert.ToUInt32(e);
    var secondNum = Convert.ToUInt32(flags);

    if (set)
        firstNum |= secondNum;

    else
        firstNum &= ~secondNum;

    var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType);

    if (!typeCheck)
    {
        var values = Enum.GetValues(typeof(tEnum));
        var lastValue = (tEnum)values.GetValue(values.Length - 1);

        if (newValue.CompareTo(lastValue) > 0)
            return lastValue;
    }

    return newValue;
}

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

public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
    SetFlags(e, flags, true);
}

public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
    SetFlags(e, flags, false);
}

Это изменит типы Enum s, как вы пытаетесь сделать.

public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
    return SetFlags(e, default(tEnum), true, false);
}

Имейте в виду, однако, что вы МОЖЕТЕ конвертировать между любым Enum и любым другим Enum, используя этот метод, даже те, которые не имеют флагов. Например:

public enum Turtle
{
    None = 0,
    Pink,
    Green,
    Blue,
    Black,
    Yellow
}

[Flags]
public enum WriteAccess : short
{
   None = 0,
   Read = 1,
   Write = 2,
   ReadWrite = 3
}

static void Main(string[] args)
{
    WriteAccess access = WriteAccess.ReadWrite;
    Turtle turtle = access.ChangeType<Turtle>();
}

Переменная turtle будет иметь значение Turtle.Blue.

Однако при использовании этого метода существует безопасность от неопределенных Enum значений. Например:

static void Main(string[] args)
{
    Turtle turtle = Turtle.Yellow;
    WriteAccess access = turtle.ChangeType<WriteAccess>();
}

В этом случае access будет установлено на WriteAccess.ReadWrite, поскольку максимальное значение WriteAccess Enum составляет 3.

Еще один побочный эффект смешивания Enum s с FlagsAttribute и без него состоит в том, что процесс преобразования не приведет к совпадению значений 1: 1.

public enum Letters
{
    None = 0,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H
}

[Flags]
public enum Flavors
{
    None = 0,
    Cherry = 1,
    Grape = 2,
    Orange = 4,
    Peach = 8
}

static void Main(string[] args)
{
    Flavors flavors = Flavors.Peach;
    Letters letters = flavors.ChangeType<Letters>();
}

В этом случае letters будет иметь значение Letters.H вместо Letters.D, поскольку базовое значение Flavors.Peach равно 8. Кроме того, преобразование из Flavors.Cherry | Flavors.Grape в Letters даст Letters.C, что может показаться не интуитивным.

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