2014-01-31 3 views
5

У меня есть объект. Обычно это либо long, либо string, поэтому для упрощения кода предположим именно это.Как преобразовать произвольный объект в перечисление?

Мне нужно создать метод, который пытается преобразовать этот объект в предоставленный enum. Таким образом:

public object ToEnum(Type enumType, object value) 
{ 
    if(enumType.IsEnum) 
    { 
     if(Enum.IsDefined(enumType, value)) 
     { 
      var val = Enum.Parse(enumType, (string)value); 
      return val; 
     } 
    } 
    return null; 
} 

Со строками это хорошо работает. С номерами он вызывает проблемы, потому что тип по умолчанию для перечисления по умолчанию - int, а не long и IsDefined - throws a ArgumentException.

Конечно, я могу сделать много проверок, конверсий или пробных уловов.

Я хочу, чтобы для этого был чистый и маленький код. Любые идеи, как сделать его читабельным и простым?

+2

вы проверили http://stackoverflow.com/a/29489/395890 – AMember

+0

Ну, я должен сделать это динамически (я не знаю, тип перечисления в компиляции время). Кроме того, как я уже сказал, 'IsDefined' - это не-go, потому что для меня это слишком сложно. –

+0

Это хорошая привычка объяснять -1 голосов. Если что-то не так с вопросом, дайте мне знать ;-) –

ответ

4

Он чувствует ко мне, как вы только на самом деле хотите, чтобы обрабатывать три случая:

  • Input уже правильный тип
  • Струны
  • Целые в различных типах

Я считаю, что это будет делать то, что вы хотите для действительного ввода:

public object ToEnum(Type enumType, object value) 
{ 
    if (value == null) 
    { 
     throw new ArgumentNullException("value"); 
    } 
    if (enumType == null) 
    { 
     throw new ArgumentNullException("type"); 
    } 
    if (!enumType.IsEnum) 
    { 
     return false; 
    } 
    string valueString = value as string; 
    if (valueString != null) 
    { 
     return Enum.IsDefined(enumType, value) ? Enum.Parse(enumType, valueString) : null; 
    } 
    if (value.GetType() == enumType) 
    { 
     return value; 
    } 
    // This appears to handle longs etc 
    return Enum.ToObject(enumType, value); 
} 

Однако это вернет значение правильного типа даже для неопределенных значений. Если вы не хотите этого, измените последнюю часть к:

object candidate = Enum.ToObject(enumType, value); 
return Enum.IsDefined(enumType, candidate) ? candidate : null; 

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

+0

Это отличный ответ, неудивительно. Спасибо, Джон! Я пропустил этот метод ToObject. Фактически, количество доступных перегрузок обрабатывает несколько «если бы я хотел этого избежать». Честно говоря, в первый раз я обнаружил, что базовый класс для (целочисленных) чисел будет аккуратным ;-) Еще раз спасибо. –

+0

@PiotrZierhoffer: Если вы много работаете с перечислениями, вы можете найти мою библиотеку Unconstrained Melody: https://code.google.com/p/unconstrained-melody/ –

+0

выглядит интересно, спасибо! Как я вижу на вашей странице, ему нужна некоторая обработка после сборки, что может быть немного неприятным для Mono. Но я часто сталкивался с такими проблемами ... –

0

Попробуйте

public object ToEnum<T>(object value) 
    { 
     var type = typeof(T); 

     if (type.IsEnum) 
     { 
      int numberVal; 

      if (!int.TryParse(value.ToString(), out numberVal) && value.GetType() != typeof(string)) 
      { 
       return null; 
      } 

      value = numberVal; 

      if (Enum.IsDefined(type, value)) 
      { 
       T result = (T)Enum.Parse(type, value.ToString()); 
       return result; 
      } 
     } 
     return null; 
    } 
+0

На самом деле, для включения строковых значений (т. Е. Имен полей, а не только целочисленных значений) потребуется немного переделать. И преобразование int в строку в int чувствует себя плохо для меня, как неправильный способ пойти ... Но спасибо в любом случае :) –

Смежные вопросы