Ограничения типа перечисления в C# [дубликат]
Возможные Дубликаты:
кто-нибудь знает хороший обходной путь для отсутствия общего ограничения перечисления?
в чем причина того, что C# не разрешает ограничения типа на Enum ' s? Я уверен, что за этим безумием стоит какой-то метод, но я хотел бы понять, почему это невозможно.
ниже то, что я хотел бы быть в состоянии сделать (в теории).
public static T GetEnum<T>(this string description) where T : Enum
{
...
}
6 ответов:
Это иногда востребованная функция.
Как я люблю указывать, все функции не реализованы, пока кто-то не разработает, спецификации, инструменты, тесты, документы и не отправит эту функцию. До сих пор никто не сделал для этого. Нет никакой особенно необычной причины, почему бы и нет; у нас есть много других вещей, ограниченных бюджетов, и этот никогда не проходил мимо "разве это не было бы хорошо?"обсуждение в команде языкового дизайна.
CLR не поддерживает его, поэтому, чтобы заставить его работать, нам нужно будет выполнять работу во время выполнения в дополнение к языковой работе.(см. комментарии к ответам)Я вижу, что есть несколько достойных случаев использования, но ни один из них не настолько убедителен, чтобы мы выполняли эту работу, а не одну из сотен других функций, которые гораздо чаще запрашиваются или имеют более убедительные и далеко идущие случаи использования. (Если мы собираемся гадить с этим кодом, я бы лично расставил приоритеты делегата ограничения путь, путь выше перечисления ограничений.)
на самом деле, это возможно, с уродливым трюком. Однако его нельзя использовать для методов расширения.
public abstract class Enums<Temp> where Temp : class { public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp { return (TEnum)Enum.Parse(typeof(TEnum), name); } } public abstract class Enums : Enums<Enum> { } Enums.Parse<DateTimeKind>("Local")если вы хотите, вы можете дать
Enums<Temp>частный конструктор и публичный вложенный абстрактный унаследованный класс сTempкакEnum, чтобы предотвратить унаследованные версии для не-перечислений.обратите внимание, что вы не можете использовать этот трюк, чтобы сделать методы расширения.
public static T GetEnum<T>(this string description) where T : struct { return (T)Enum.Parse(typeof(T), description); }это ответ на твой вопрос?
Il ткачество с помощью ExtraConstraints
Код
public static T GetEnum<[EnumConstraint] T>(this string description) { ... }что компилируется
public static T GetEnum<T>(this string description) where T : Enum { ... }
вот VB.NET версия Слаки отличный уродливый трюк С
Importsкак "typedef": (Вывод типа работает как ожидалось, но вы не можете получить методы расширения.)'Base namespace "EnumConstraint" Imports Enums = EnumConstraint.Enums(Of System.Enum) Public NotInheritable Class Enums(Of Temp As Class) Private Sub New() End Sub Public Shared Function Parse(Of TEnum As {Temp, Structure})(ByVal Name As String) As TEnum Return DirectCast([Enum].Parse(GetType(TEnum), Name), TEnum) End Function Public Shared Function IsDefined(Of TEnum As {Temp, Structure})(ByVal Value As TEnum) As Boolean Return [Enum].IsDefined(GetType(TEnum), Value) End Function Public Shared Function HasFlags(Of TEnum As {Temp, Structure})(ByVal Value As TEnum, ByVal Flags As TEnum) As Boolean Dim flags64 As Long = Convert.ToInt64(Flags) Return (Convert.ToInt64(Value) And flags64) = flags64 End Function End Class Module Module1 Sub Main() Dim k = Enums.Parse(Of DateTimeKind)("Local") Console.WriteLine("{0} = {1}", k, CInt(k)) Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k)) k = DirectCast(k * 2, DateTimeKind) Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k)) Console.WriteLine(" {0} same as {1} Or {2}: {3} ", IO.FileAccess.ReadWrite, IO.FileAccess.Read, IO.FileAccess.Write, _ Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileAccess.Read Or IO.FileAccess.Write)) ' These fail to compile as expected: 'Console.WriteLine(Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess)) 'Console.WriteLine(Enums.HasFlags(Of IO.FileAccess)(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess)) If Debugger.IsAttached Then _ Console.ReadLine() End Sub End Moduleвыход:
Local = 2 IsDefined(Local) = True IsDefined(4) = False ReadWrite same as Read Or Write: True
одна причудливая вещь здесь заключается в том, что существует достаточное количество общих методов перечисления, которые вы можете написать, реализация которых зависит от "базового" типа перечисления.
по "базовому" типу перечисления,
E, Я имею в виду типа вSystemпространство имен, имя которого совпадает с именем членаSystem.TypeCodeперечисление получить по телефонуSystem.Type.GetTypeCode(System.Type)для типаE. Если перечисление было объявлено в C#, это тот же тип, что было объявлено, что "наследует" от (Я не уверен, что это официально называется в спецификации). Например, базовый типAnimalниже перечислениеSystem.Byte:public enum Animal : byte { Moose, Squirrel }можно писать такие методы с помощью операторов switch, но это, конечно, уродливо, вы не можете получить строго типизированные параметры или возвращаемые типы, тип которых является базовым типом перечисления, и вам нужно либо повторить поиск метаданных, либо сделать некоторое кэширование (например, в статическом конструкторе для универсального типа содержащий метод).
Comments