Конвертировать перечисление в другой тип перечисления

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

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

Ответ 1

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

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

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

Ответ 2

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

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

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

Enum2 value2 = (Enum2)value;

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

Ответ 3

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

Gender2 gender2 = (Gender2)((int)gender1);

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

Если мы имеем:

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;

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

Ответ 7

вы могли бы написать простую функцию, такую ​​как:

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

Ответ 8

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

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

// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();

Ответ 9

Я написал набор методов расширения a while back, которые работают для нескольких различных типов 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, которые вы пытаетесь сделать.

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.

Однако с помощью этого метода существует безопасность от undefined Enum. Например:

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

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

Другим побочным эффектом смешивания Enum с 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, который может казаться неинтуитивным.

Ответ 10

Вы можете использовать ToString(), чтобы преобразовать первое перечисление в его имя, а затем Enum.Parse(), чтобы преобразовать строку обратно в другую Enum. Это вызовет исключение, если значение не поддерживается перечислением назначения (т.е. Для значения "Неизвестно" )

Ответ 11

Я знаю, что старый вопрос и много ответов. Однако я считаю, что использование оператора switch, как и в принятом ответе, несколько громоздко, поэтому вот мои 2 цента:

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

var genderTranslator = new Dictionary<TheirGender, MyGender>();
genderTranslator.Add(TheirGender.Male, MyGender.Male);
genderTranslator.Add(TheirGender.Female, MyGender.Female);
genderTranslator.Add(TheirGender.Unknown, MyGender.Unknown);

// translate their to mine    
var myValue = genderTranslator[TheirValue];

// translate mine to their
var TheirValue = genderTranslator .FirstOrDefault(x => x.Value == myValue).Key;;

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

public static class EnumTranslator
{

    private static Dictionary<TheirGender, MyGender> GenderTranslator = InitializeGenderTranslator();

    private static Dictionary<TheirGender, MyGender> InitializeGenderTranslator()
    {
        var translator = new Dictionary<TheirGender, MyGender>();
        translator.Add(TheirGender.Male, MyGender.Male);
        translator.Add(TheirGender.Female, MyGender.Female);
        translator.Add(TheirGender.Unknown, MyGender.Unknown);
        return translator;
    }

    public static MyGender Translate(this TheirGender theirValue)
    {
        return GenderTranslator[theirValue];
    }

    public static TheirGender Translate(this MyGender myValue)
    {
        return GenderTranslator.FirstOrDefault(x => x.Value == myValue).Key;
    }

}