C#: перечисления в интерфейсах

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

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

У меня есть класс ответа, который в настоящее время содержит перечисление для кода ошибки и строкового описания. Коды ошибок определяют довольно хороший и полный набор ответов, которые все очень семантически связаны с операциями, где они используются.

Unfortuantely, я теперь должен добавить другой рабочий процесс для подобного набора объектов API, и это потребует строкового описания, которое прекрасно, но также и перечислимый код ошибки, состоящий из полностью несвязанного набора кодов ошибок. Коды ошибок (и другие аспекты объектной модели) будут использоваться в большом количестве тех же классов, таким образом, было бы хорошо получить движение интерфейса так, чтобы я мог выполнить объекты через ту же платформу.

Намерение здесь состоит в том, чтобы сделать контракт, в котором говорится, что "У меня есть код ошибки и описание того кода ошибки".

Однако насколько я знаю, что нет никакого способа добавить объект к интерфейсу такой как

public interface IError
{
    enum ErrorCode;
    string Description;
}

и при этом нет способа выразить

public interface IError<T> where T: enum
{
    T ErrorCode;
    string Description;
}

Кто-либо каждый столкнутый что-то вроде этого прежде?

18
задан bwerks 30 June 2010 в 20:39
поделиться

4 ответа

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

Это возможно выразить ваш общий интерфейс - только не на C #. Вы можете сделать это в IL без проблем. Я надеюсь, что это ограничение может быть снято в C # 5. Насколько я видел, компилятор C # действительно правильно обрабатывает ограничение.

Если вы действительно хотите использовать это как вариант, вы можете использовать код, аналогичный тому, что был в Unconstrained Melody , библиотеке, которая у меня есть, которая предоставляет различные методы с этим труднодостижимым ограничением. . Он эффективно использует переписывание IL - он грубый, но он работает для единой системы обмена сообщениями и, вероятно, сработает и для вас. Вы, вероятно, захотите поместить интерфейс в отдельную сборку, что было бы несколько неудобно.

Конечно, вы могли бы вместо этого сделать свой интерфейс просто T: struct ... это было бы не идеально, но, по крайней мере, несколько ограничивало бы тип . Пока вы можете удостовериться, что им не злоупотребляют, это будет работать достаточно хорошо.

14
ответ дан 30 November 2019 в 08:21
поделиться

Как упомянул Джон Скит, базовый IL поддерживает ограничение обобщенных типов перечислениями, однако C # не позволяет вам воспользоваться этим.

Однако F # допускает такого рода ограничения. Кроме того, если интерфейс определен в F #, ограничение будет применено в коде C #, реализующем интерфейс.Если вы хотите смешивать языки в своем решении, что-то вроде этого должно работать нормально:

type IError<'T when 'T :> System.Enum and 'T : struct> =
    abstract member Error : 'T
    abstract member Description : string

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

8
ответ дан 30 November 2019 в 08:21
поделиться

Неспособность написать публичный интерфейс IError , где T: enum - это то, на что мы все жаловались годами. Пока в этом направлении нет прогресса.

Обычно я пишу public interface IError и оставляю примечание для разработчика, что T должно быть перечислением.

1
ответ дан 30 November 2019 в 08:21
поделиться

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

public interface IError<TEnum> where T: struct
{
    T ErrorCode;
    string Description;
}
1
ответ дан 30 November 2019 в 08:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: