Следует ли использовать общие ограничения для использования интерфейсов в качестве типов параметров?
Рассмотрим эту тривиальную функцию:
public static bool IsPositive(IComparable<int> value)
{
return value.CompareTo(0) > 0;
}
Теперь, если я передаю int
этому методу, он получает коробку. Не было бы поэтому лучше определить вышеупомянутый метод следующим образом:
public static bool IsPositive<T>(T value) where T : IComparable<int>
{
return value.CompareTo(0) > 0;
}
Используя общее ограничение таким образом, я могу достичь точно такой же функциональности, как и код выше, с дополнительным преимуществом, которое не требует бокса (так как вызов IsPositive<int>
принимает параметр типа int
).
Приведенный выше примерный код явно не имеет смысла. Но мой более широкий вопрос: , не всегда ли смысл определять методы последним способом (используя общее ограничение, а не иметь параметр какого-либо типа интерфейса), чтобы избежать потенциального бокса типов значений?
Я подозреваю, что ответ скорее всего будет "да", но он требует большего набора текста, и во многих случаях встретить тип значения будет очень маловероятным, например, когда метод принимает некоторые IEnumerable<T>
. " Но мне интересно, есть ли большая разница между этими подходами, которые ускользают от меня в данный момент.
Ответы
Ответ 1
Одна проблема заключается в том, что общий ограничитель не является частью подписи. Если у вас есть...
static T Method<T>(T value) where T : ICompareable<int>
... и...
static T Method<T>(T value) where T : IEnumerable<int>
... у компилятора не было бы способа узнать, что есть.
И чтобы вызвать Эрика Липперта...
Ответ 2
В комментариях к вопросу возникла некоторая путаница в вопросе о том, вызывает ли вызов метода метод бокса после передачи аргумента.
Когда вы вызываете виртуальный метод выражения, тип которого является параметром типа с ограничением на него, компилятор С# испускает команду constrained.callvirt
. Как можно надеяться, это делает правильные вещи; бокс происходит только тогда, когда это абсолютно необходимо.
Подробнее о точной семантике бокса связанных виртуальных вызовов читайте в документации:
http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.constrained.aspx
Ответ 3
Другая проблема будет заключаться в том, что общее ограничение относится к параметрическим типам параметризованного типа, таким как
static bool AreAllTheSame<T>(IEnumerable<T> something)
where T : IEquatable<T>
Не всегда возможно преобразовать параметр типового типа таким образом, если вы не вводите параметр второго типа, например:
static bool AreAllTheSame<S, T>(S something)
where S : IEnumerable<T>
where T : IEquatable<T>
Это просто не выглядит правильным.