Страницы

Поиск по вопросам

четверг, 2 января 2020 г.

Как в обобщенном классе (generic) задать ограничение “только float или int” для типа?

#c_sharp #net #generics


Есть класс Parameter:

public abstract class Parameter
{
    public T Value { get; }
    //...
}


Как в таком классе для типа T задать ограничение только на определенные базовые типы?
Хотелось бы иметь что-то наподобие этого:

public abstract class Parameter where T : int, float, double, string
{
    public T Value { get; }
    //...
}


IntelliSense сразу ругается на каждый тип:


  "int" не является допустимым ограничением. Тип, использованный в
  качестве ограничения, должен быть интерфейсом, незапечатанным классом
  или параметром-типом.


UPD. Или просто оставить тип без ограничений и ничего страшного в этом нет, что можно
случайно создать класс с не таким типом, который ожидалось видеть?

UPD 2. Отвечаю на вопрос для какой цели нужно ограничение типа. Есть некоторая абстракция
Параметр, которая инкапсулирует в себе данные определенного базового типа. У него есть
поля Значение, Имя и Максимальное и минимальное значение. Читая ответы на вопросы,
я понял, что нет смысла ограничивать данный тип параметра.
    


Ответы

Ответ 1



Есть несколько причин, по которым этот код не может работать в C# where T : int, float, double, string Когда вы указываете ограничение T : Type то это значит, что T может быть как типа Type так и потомком типа Type. Следовательно, конструкция where T : int, float семантически означает следующее — тип T должен наследовать от типов int и float. Это не сработает по двум причинам: В C# запрещено множественное наследование Конструкция T : int не может работать, так как int это структура, а структуры не поддерживают наследование. Это свойство классов. Можете проверить это на примере: Generic where T : struct where U : T. (замените struct на class и все заработает) Зато компилятор предлагает вам рабочие варианты: Тип, использованный в качестве ограничения, должен быть интерфейсом, незапечатанным классом или параметром-типом. Cтруктуры и классы могут имплементировать интерфейсы, поэтому ограничение типа на интерфейс может иметь смысл как для структур, так и для классов, например в ограничение T : IComparable можно подставить как int так и string так как оба этих типа имплементируют этот интерфейс. Или просто оставить тип без ограничений и ничего страшного в этом нет, что можно случайно создать класс с не таким типом, который ожидалось видеть Для этого следует ответить на вопрос, для чего вы задаете ограничение типа? Вы видите что-то общее между типами int и string? Вы хотите обращаться к общим членам этих типов или использовать их как-то иначе в полиморфном контексте? Если нет, то, наверное, и нет смысла искусственно ограничивать тип-параметр.

Ответ 2



К сожалению, никак. Можно использовать только constraints указанные в документации: https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters В качестве обходного пути можно создать класс-обёртку для нужных типов: public class WrappedInt { public int Value { get; } public WrappedInt(int value) { this.Value = value; } } public class Foo where T : WrappedInt, WrappedFloat, ... { public Foo(T ariphmeticValue) { } } UPD. Касаемо последнего вопроса: сильно зависит от задачи. Если использование других типов будут вызывать unhandled exceptions - это плохо.

Комментариев нет:

Отправить комментарий