Итак, у меня есть этот класс:
public class Foo<T> where T : ???
{
private T item;
public bool IsNull()
{
return item == null;
}
}
Теперь я ищу ограничение типа, которое позволяет мне использовать в качестве параметра типа все, что может быть null
. Это означает все ссылочные типы, а также все типы Nullable
( T?
):
Foo<String> ... = ...
Foo<int?> ... = ...
должно быть возможно.
Использование class
в качестве ограничения типа позволяет мне использовать только ссылочные типы.
Дополнительная информация:
я пишу приложение каналов и фильтров и хочу использовать null
ссылку в качестве последнего элемента, который передается в конвейер, чтобы каждый фильтр мог нормально отключаться, выполнять очистку и т. Д.
IFoo<T>
в качестве рабочего типа и создавать экземпляры с помощью фабричного метода? Это можно было заставить работать.Ответы:
Если вы хотите выполнить проверку времени выполнения в конструкторе Foo, а не проверять время компиляции, вы можете проверить, не является ли тип ссылочным или допускающим значение NULL, и в этом случае создать исключение.
Я понимаю, что только проверка времени выполнения может быть неприемлемой, но на всякий случай:
Затем следующий код компилируется, но последний (
foo3
) вызывает исключение в конструкторе:источник
static bool isValidType
поле, которое вы установили в статическом конструкторе, затем просто проверьте этот флаг в конструкторе экземпляра и бросьте, если это недопустимый тип, чтобы вы не выполняли всю работу по проверке каждый раз, когда вы создаете экземпляр. Я часто использую этот паттерн.Я не знаю, как реализовать эквивалент OR в дженериках. Однако я могу предложить использовать ключевое слово по умолчанию , чтобы создать значение null для типов, допускающих значение NULL, и значение 0 для структур:
Вы также можете реализовать свою версию Nullable:
Пример:
источник
Я столкнулся с этой проблемой из-за более простого случая, когда мне нужен общий статический метод, который мог бы принимать все, что допускает значение NULL (ссылочные типы или Nullables), что привело меня к этому вопросу без удовлетворительного решения. Итак, я придумал свое собственное решение, которое было относительно проще решить, чем заданный в OP вопрос, просто имея два перегруженных метода, один из которых принимает a
T
и имеет ограничение,where T : class
а другой принимаетT?
и имеетwhere T : struct
.Затем я понял, что это решение также может быть применено к этой проблеме для создания решения, которое можно проверить во время компиляции, сделав конструктор закрытым (или защищенным) и используя статический фабричный метод:
Теперь мы можем использовать это так:
Если вам нужен конструктор без параметров, вы не получите тонкости перегрузки, но вы все равно можете сделать что-то вроде этого:
И используйте это так:
У этого решения есть несколько недостатков, один из них заключается в том, что вы можете предпочесть использовать «новый» для создания объектов. Другим является то , что вы не будете в состоянии использовать в
Foo<T>
качестве общего аргумента типа для типа ограничения что - то вроде:where TFoo: new()
. Наконец, вам нужен дополнительный код, который может увеличиться, особенно если вам нужно несколько перегруженных конструкторов.источник
Как уже упоминалось, у вас не может быть проверки во время компиляции. Общие ограничения в .NET сильно отсутствуют и не поддерживают большинство сценариев.
Однако я считаю, что это лучшее решение для проверки во время выполнения. Его можно оптимизировать во время JIT-компиляции, поскольку они оба константы.
источник
Такое ограничение типа невозможно. Согласно документации по ограничениям типов, не существует ограничения, которое фиксирует как допускающие значение NULL, так и ссылочные типы. Поскольку ограничения можно комбинировать только в сочетании, невозможно создать такое ограничение путем комбинации.
Однако для ваших нужд вы можете вернуться к параметру неограниченного типа, поскольку вы всегда можете проверить == null. Если тип является типом значения, проверка всегда будет иметь значение false. Тогда вы, возможно, получите предупреждение R # «Возможное сравнение типа значения с null», что не критично, если семантика вам подходит.
Альтернативой может быть использование
вместо проверки на null, поскольку default (T), где T: class всегда имеет значение null. Это, однако, означает, что вы не можете отличить погоду: значение, не допускающее значения NULL, никогда не задавалось явно или было просто установлено значение по умолчанию.
источник
я использую
источник
источник