Метод расширения для обнуляемого перечисления из строки

#c# #.net #generics #enums

#c# #.net #обобщения #перечисления

Вопрос:

Я преобразую перечисление одного класса в перечисление другого класса с помощью приведенного ниже кода:

 var someClassA.MyEnumA = (MyEnumA)Enum.Parse(typeof(MyEnumA), someClassB.MyEnumA.ToString());
  

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

     public static T EnumFromString<T>(string value)
    {
        return (T)Enum.Parse(typeof(T), value);
    }
  

Затем в той же строке выше используется:

 var someClassA.MyEnumA = EnumFromString<MyEnumA>(someClassB.MyEnumA.ToString());
  

Это прекрасно работает. Однако теперь у меня есть код, в котором я могу иметь nullable Enum. Итак, мой текущий код:

                 if (someClassB.MyEnumX.HasValue)
                {
                    someClassA.MyEnumX = (MyEnumX)Enum.Parse(typeof(MyEnumX),someClassB.MyEnumX.ToString());
                }
  

Я не уверен, как обновить мой текущий вспомогательный метод для обработки обоих сценариев — или было бы проще просто написать другой вспомогательный метод с именем NullableEnumFromString — я не уверен, как это будет работать или даже возможно с дженериками?

Комментарии:

1. Я немного смущен. Каков тип свойства MyEnumA в SomeClassA и MyEnumA в SomeClassB?

2. разве вы не можете проверить value и вернуть null if string.IsNullOrEmpty(value) в своем вспомогательном методе?

3. Для обработки nullable enums вы хотите использовать тип <T?> и ограничение where T : struct

4. Кроме того (и в дополнение к другим комментариям) вам нужно будет концептуально решить, что вы хотите делать с null? как это соотносится? вы просто собираетесь использовать значение по умолчанию или собираетесь указать значение по умолчанию.

5. Почему бы не использовать someClassA.MyEnumX = someClassB.MyEnumX; вместо этого? Почему требуется сопоставление через строку?

Ответ №1:

Мне кажется, что основная проблема здесь заключается в том, что к моменту вызова метода преобразования вы уже преобразовали значение enum в a string , и поэтому у вас нет способа узнать, каким был исходный тип, не говоря уже о том, чтобы обрабатывать nullable enum тип.

Мне это также кажется неудобным только с точки зрения того, что все вызывающие должны вызывать ToString() себя.

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

 public static TResult Convert<T, TResult>(this T value)
    where T : struct, System.Enum
    where TResult : struct, System.Enum
{
    return (TResult)Enum.Parse(typeof(TResult), value.ToString());
}

public static TResult? Convert<T, TResult>(this T? value)
    where T : struct, System.Enum 
    where TResult : struct, System.Enum
{
    return value != null ?
        (TResult?)Enum.Parse(typeof(TResult), value.ToString()) : null;
}
  

Примечания:

  • В приведенном выше примере используется функция C # 7.3, которая допускает ограничение на System.Enum . Если вы используете более раннюю версию C #, просто опустите это. Он все равно будет работать, но просто не будет иметь такой же степени безопасности типов во время компиляции.
  • Хотя все четыре ограничения параметра типа указывают struct , строго говоря, это необходимо только для второй версии с nullable-enum . В первой версии это ничего не повредило; Я просто вставил это для согласованности.
  • Этот метод расширения nullable-enum возвращает null , если входное значение равно null . В вашем вопросе не указано, какое значение вы бы использовали в этом случае. Вы можете использовать любой запасной вариант, который вам нравится, если это не то, что вы хотели сделать.