Обновление: См. нижнюю часть этого вопроса для обходного пути С#.
Привет,
Рассмотрим следующий метод расширения:
public static bool HasFlags<T>(this T value, T flags)
where T : System.Enum
{
// ...
}
Это, как вы, возможно, знаете, выкидывает ошибку во время компиляции, так как классу обычно не разрешается наследовать от System.Enum
. Проблема в том, что любое перечисление, указанное с использованием ключевого слова enum
, действительно наследует от System.Enum
, поэтому приведенный выше код был бы идеальным способом ограничить метод расширения только перечислениями.
Теперь очевидно, что здесь нужно использовать enum
вместо T
, но затем вы теряете преимущества родовых типов:
MyEnum e;
e.HasFlags(MyOtherEnum.DoFunkyStuff);
Вышеприведенный код будет генерировать ошибку времени компиляции с использованием общих типов, в то время как он может вызывать только ошибку времени выполнения, используя тип enum
(если я его реализую).
Существуют ли какие-либо параметры компилятора, которые можно использовать для отключения проверки ограничений, или есть ли другой отличный способ сделать это?
Прежде чем это будет предложено, я хотел бы сказать, что я не буду использовать where T : struct
или некоторые такие, так как тогда вы сможете делать такие странные вещи, как 123.HasFlags(456)
.
Я в тупике, почему эта ошибка существует вообще... Это та же проблема, с которой вы могли бы воспользоваться where T : System.Object
, но для этого у вас есть where T : class
... Почему нет where T : enum
?
Обходное решение С#
Jon Skeet начал работу над библиотекой, которая компилирует классы с ограничением на
IEnumConstraint
, который затем заменяется наSystem.Enum
post-build. Это, я считаю, самый близкий, кто может решить эту проблему в настоящее время.См:
- Код проекта: http://code.google.com/p/unconstrained-melody/
- Запись в блоге: http://msmvps.com/blogs/jon_skeet/archive/2009/09/10/generic-constraints-for-enums-and-delegates.aspx
Если это обходное решение неосуществимо, вам придется написать свою библиотеку как код С++/CLI, который не ограничивает того, что можно использовать для ограничений типа generic (см. код в моем ответе ниже.)