C # - Возвращение Enum? из метода статического расширения - PullRequest
3 голосов
/ 13 октября 2009

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

public static Enum ToEnum<T>(this string s)
{
    return (Enum)Enum.Parse(typeof(T), s);
}

public static bool IsEnum<T>(this string s)
{
    return Enum.IsDefined(typeof(T), s);
}

Примечание. Из-за ограничений общих типов я должен написать методы, подобные приведенным выше. Я хотел бы использовать T ToEnum (эту строку s), где T: Enum, чтобы избежать приведения после выполнения вызова ... но никто не может этого сделать.

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

public static Enum? ToEnumSafe<T>(this string s)
{
    return (IsEnum<T>(s) ? (Enum)Enum.Parse(typeof(T), s) : null);
}

Однако из-за ошибок компилятора это не разрешено.

error CS0453: The type 'System.Enum' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'

Я должен признать, что я немного запутался здесь, как Enum? должно быть законное возвращаемое значение, нет? Я пробовал что-то подобное, но в конечном итоге с той же ошибкой.

public static T? ToEnumSafe<T>(this string s)
{
    return (IsEnum<T>(s) ? (T)Enum.Parse(typeof(T), s) : null);
}

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

public static bool IsEnum(this string s, Type T)
{
    return Enum.IsDefined(T, s);
}
public static Enum? ToEnumSafe(this string s, Type T)
{
    return (IsEnum(s, T) ? (Enum)Enum.Parse(T, s) : null);
}

Я что-то упускаю здесь действительно глупо?

Ответы [ 4 ]

5 голосов
/ 13 октября 2009

Попробуйте:

public static T? ToEnumSafe<T>(this string s) where T : struct
{
    return (IsEnum<T>(s) ? (T?)Enum.Parse(typeof(T), s) : null);
}
3 голосов
/ 13 октября 2009

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

Хотя C # не поддерживает общие ограничения, чтобы сказать, что T должен быть типом enum, CLR поддерживает. У меня есть проект под названием Unconstrained Melody , который представляет собой библиотеку «полезных вещей, которые можно сделать с помощью enum». Я подозреваю, что он уже справляется с тем, что вы хотите (при условии, что вам нужно использовать только names в перечислении, а не строковые представления целочисленных значений). Хотя у него нет IsDefined(string), у него есть TryParse, который будет выполнять ту же работу.

Подробнее см. в этом блоге .

Относительно того, почему Enum? не является допустимым типом возврата - System.Enum сам по себе является ссылочным типом (так же, как System.ValueType), поэтому он уже может иметь значение null. Вы можете использовать ? только с необнуляемыми типами значений.

0 голосов
/ 13 октября 2009

Enum не является отдельным типом в .Net, это просто заполнитель для конкретного типа значения (int, если вы не указали иначе).

Это означает, что вы вообще не можете использовать его как объявление типа (независимо от того, используется метод статического расширения или нет).

0 голосов
/ 13 октября 2009
public static Enum ToEnum<T>(this string s)
{
    return (Enum)Enum.Parse(typeof(T), s);
}

должно быть

public static T ToEnum<T>(this string s)
{
    return (T)Enum.Parse(typeof(T), s);
}

также может исправить следующее

public static Enum? ToEnumSafe<T>(this string s)
{
    return (IsEnum<T>(s) ? (Enum)Enum.Parse(typeof(T), s) : null);
}

до

public static T? ToEnumSafe<T>(this string s)
    where T : struct
{
    return (IsEnum<T>(s) ? (T?)Enum.Parse(typeof(T), s) : null);
}
...