Разница между общим аргументом, ограниченным интерфейсом, и просто использованием интерфейса - PullRequest
12 голосов
/ 27 февраля 2009

Какая разница между:

void MyMethod(IMyInterface value)
{
    //...
}

и это:

void MyMethod<T>(T value) where T : IMyInterface
{
    //...
}

Ответы [ 7 ]

11 голосов
/ 27 февраля 2009

Основное функциональное отличие состоит в том, что вы можете знать фактический тип объекта внутри универсального метода. Параметр T будет содержать фактический тип, который может быть выгоден в определенных сценариях.

В неуниверсальном случае вы не можете гарантировать доступ к базовому типу объекта. Большую часть типа вы можете получить value.GetType (), но пользователь может передать Null и помешать вам.

7 голосов
/ 27 февраля 2009

Джаред упомянул некоторые из пунктов; еще один интересный: с помощью дженериков вы можете избежать упаковки типов значений , если вы в принципе не трогаете его ... так что я мог бы получить struct Foo : IMyInterface и передать его, и он выиграл в штучной упаковке.

Разница становится более заметной с такими вещами, как коллекции:

static void Foo(IEnumerable<IMyInterface> data) {}

против

static void Foo<T>(IEnumerable<T> data) 
    where T : IMyInterface {}

Теперь, поскольку в C # 3.0 нет ковариации (за исключением массивов), я не могу передать List<Bar> в верхнюю, даже если Bar : IMyInterface - но я могу со вторым (неявным T = Bar ).

3 голосов
/ 27 февраля 2009

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

class Dictionary<TKey,TVal>
    where TKey: IComparable, IEnumerable
    where TVal: IValue
{ ... }
3 голосов
/ 27 февраля 2009

Для общей версии потребуется .NET 2.0.

А если серьезно, то, хотя они выглядят одинаково, между ними есть фундаментальные различия. Одно из отличий состоит в том, что во время выполнения JIT-компилятор будет генерировать код для каждого типа значения, который будет использоваться для универсальной версии. Неуниверсальная версия требует, чтобы типы значений были упакованы в боксы для передачи в функцию.

Разница также будет иметь значение при работе с делегатами. Подпись MyMethod<int> соответствует void MyDelegate(int x), а неуниверсальная версия не соответствует.

1 голос
/ 02 сентября 2013

Другое тонкое отличие состоит в том, что вы не можете перегружать метод только для ограничений (ограничения не являются частью сигнатуры метода):

Это незаконно:

void MyMethod<T>(T value) where T : IMyInterface
{
    //...
}

void MyMethod<T>(T value) where T : IMyInterface2
{
    //...
}

пока это законно:

void MyMethod(IMyInterface value)
{
    //...
}

void MyMethod(IMyInterface2 value)
{
    //...
}
0 голосов
/ 02 сентября 2013

Еще одно отличие для универсальных методов в целом (хотя и не для вашего примера) состоит в том, что если у одного есть метод, подобный T MungeThing<T>(T it) where T:IMungeable<T>, а класс Fnord реализует IMungeable<Fnord>, то код сможет сказать: Fnord thing1, thing2; ... thing1 = MungeThing(thing2); и компилятор будет знать, что MungeThing вернет Fnord, а не произвольную реализацию IMungable.

0 голосов
/ 27 февраля 2009

Другим предостережением, которое следует учитывать в этом сценарии, является тот факт, что использование «где T: <% вашего базового интерфейса или абстракции%>» может быть чрезмерно использовано в обобщениях, делая ваш универсальный тип не универсальным по своей природе.

IE: Помните, что изолируя ваш универсальный метод от IMyInterface, вы изолируете этот метод только от тех типов, которые реализуют IMyInterface. Так что, если вы просто решили использовать IMyInterface, основанный на хороших принципах ООП, но у вас есть только один (или в некоторых случаях очень небольшое количество) потенциальный тип в любом месте, который будет реализовывать этот интерфейс, то вы победили цель использования дженериков. При таких обстоятельствах первый вариант будет лучше.

Используйте «где» только для вашего универсального типа, когда вы собираетесь использовать более широкий диапазон типов, которые фактически реализуют IMyInterface.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...