Enum как общее ограничение: по какой причине Microsoft не хотела его реализовывать? - PullRequest
2 голосов
/ 21 апреля 2010

Я понимаю, что enum нельзя использовать как общее ограничение, и Microsoft отказалась исправить эту ошибку .

Есть причина почему?

Ответы [ 3 ]

3 голосов
/ 21 апреля 2010

Ссылка, которую вы разместили, говорит, почему:

и является несколько произвольным ограничением языка

Потенциально изменится:

Если мы когда-нибудь снова откроем ограничения как функцию, это будет одна из вещей, которую мы будем переоценивать. В следующем выпуске у нас нет возможности добавить дополнительные языковые функции, поэтому вы увидите, что это решено как «Не исправлять», но оно останется в наших списках для дальнейшего рассмотрения.

2 голосов
/ 12 января 2013

Я подозреваю, что причина, по которой enum не принимается в качестве общего ограничения, заключается в том, что хотя есть некоторые вещи, которые можно «ожидать» сделать с параметром с ограничением на перечисление, чего нельзя сделать с неограниченным параметр, единственный, который действительно будет работать, будет вызывать очень медленный неуниверсальный HasFlag; в частности, операции, которые включают преобразование между перечислением и связанным с ним базовым типом, не могут быть использованы. Разрешение ограничения, которое не позволяло бы программистам использовать переменные так, как они ожидали, а только добавляло возможность вызывать ужасно медленный неуниверсальный метод, казалось не стоящим.

Как таковая, я не думаю, что невозможность использовать Enum в качестве ограничения типа была бы потерей, но для добавления функции, которая не ожидалась, когда было принято решение: методы расширения и их взаимодействие с Intellisense. Если записать метод bool FlagCheck.HasAnyFlags<T>(T enum1, T enum2) where T:struct, который принимает два перечисления совпадающего типа и проверяет, содержит ли один флаги, которые также находятся в другом [можно написать такой метод примерно на порядок быстрее, чем Enum.HasFlag], он может Не имеет смысла вызывать его для параметров типа double, но единственным следствием этого является то, что такие вещи будут перехватываться во время выполнения, а не во время компиляции. Только если кто-то делает такую ​​вещь методом расширения, отсутствие ограничения перечисления становится раздражающим; в этом случае это означает, что у Intellisense нет возможности предложить HasAnyFlags для переменной типа enum без ее появления и для переменных других типов.

Кстати, я думаю, что я не согласен с философией ограничений enum по той же причине, по которой я не согласен с правилом, согласно которому нельзя ограничиваться закрытым типом. Даже если было бы бесполезно создавать универсальный параметр типа, который был бы ограничен типом, который всегда был бы запечатан, тот факт, что тип запечатан в [возможно предварительной] версии сборки, подразумевает, что это всегда будет так. Кроме того, если тип незапечатан, но имеет только конструкторы internal [вызываются с помощью фабричных методов], я не знаю, что замена его на запечатанный класс будет серьезным изменением , но для правила об ограничениях запечатанного типа .

1 голос
/ 13 ноября 2015

Проблемы базового типа и производительность допустимы, но у них есть обходные пути, а CLR и C ++ / CLI поддерживают общие ограничения перечисления. Работа с перечислениями флагов всегда была менее читабельной, чем я предпочитаю. HasFlag помогает, но, как было отмечено, есть возможности для повышения производительности.

У меня есть этот и несколько других полезных методов расширения / помощника enum здесь . Если вам действительно нужно написать метод, который ограничивает тип enum, этот язык может его обработать, и не так уж сложно научиться писать его достаточно, если подобные виды простых методов исходят из фона C # ,

Я подозреваю, что некоторые ограничения типовых перечислимых типов, с которыми я сталкивался в C ++ / CLI, как-то связаны с причинами, по которым это было сочтено "недостаточно важным". Например, отсутствуют наиболее полезные операторы, кроме присваивания. Чтобы сделать что-либо с TEnum, вы должны привести к базовому типу, который может быть дорогим в зависимости от того, как это делается. Учтите, что двоичная операция «Добавить / удалить / проверить флаг» очень быстрая, добавление требования преобразования одного типа резко меняет производительность. Переход к (известному) значению базового типа в C ++ / CLI может быть сделан очень быстро способом, который реализован в IL как эквивалент «взять в параметре enum и передать его, как если бы он был на самом деле базовый тип ". Однако сделать это обратно в enum невозможно в C ++ / CLI и требует вызова Enum.ToObject, что является дорогостоящим преобразованием.

Я реализовал обходной путь, который в основном использует набор методов "convertBackToTEnum" и переписывает IL, чтобы сделать это точно так же, как методы ConvertToUnderlyingType.

Кастинг также сопряжен с риском, если вы испортите и приведете к неверному базовому типу. Я был достаточно обеспокоен тем, что написал сценарий T4 для генерации модульных тестов для каждой операции для каждого базового типа (со значениями, которые могли бы вызвать проблемы при неправильном преобразовании).

Если вам нужно написать методы, которые поддерживают это, в приведенном выше проекте есть несколько примеров, включая ограничения классов и методов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...