Ограничения типа перечисления в C# [дубликат]




Возможные Дубликаты:
кто-нибудь знает хороший обходной путь для отсутствия общего ограничения перечисления?






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



ниже то, что я хотел бы быть в состоянии сделать (в теории).



public static T GetEnum<T>(this string description) where T : Enum
{
...
}
636   6  

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

    Ничего не найдено.