Должны ли общие ограничения предпочтительнее использовать интерфейсы в качестве типов параметров? - PullRequest
13 голосов
/ 20 августа 2010

Рассмотрим эту тривиальную функцию:

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> «.Но мне интересно, есть ли большая разница между этими подходами, которые ускользают от меня в данный момент.

Ответы [ 3 ]

8 голосов
/ 20 августа 2010

Одна из проблем связана с тем, что родовое ограничение на самом деле не является частью сигнатуры.Если у вас есть ...

static T Method<T>(T value) where T : ICompareable<int>

... и ...

static T Method<T>(T value) where T : IEnumerable<int>

... у компилятора не будет способа узнать, что есть что.

И чтобы вызвать Эрика Липперта ...

7 голосов
/ 20 августа 2010

Была некоторая путаница в комментариях к вопросу о том, вызывает ли вызов метода после аргумента.

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

Подробнее о точной семантике бокса для ограниченных виртуальных вызовов читайте в документации:

http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.constrained.aspx

0 голосов
/ 20 августа 2010

Другая проблема может возникнуть, когда универсальное ограничение на параметры универсального типа параметризованного типа, например

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>

Это выглядит не так.

...