Это чрезвычайно полезная вещь.
Например, любой из методов расширения LINQ . Они не заботятся о том, что им передано, пока это реализует IEnumerable<T>
. Идея состоит в том, что все они могут быть применены ко всему, что вы можете перечислить, используя цикл foreach
.
Представьте себе, насколько бесполезным было бы ограничение, если бы все они требовали от вас пропускать, например, T[]
массива или List<T>
объекта.
Вот только одна очень тривиальная иллюстрация. Давайте представим, что расширений LINQ не существует (что на самом деле вполне реально, если я использую .NET 2.0), и я хочу написать метод Sum
.
Я мог бы написать это так:
public static double Sum(List<double> values)
{
double sum = 0.0;
foreach (double value in values)
{
sum += value;
}
return sum;
}
Это все хорошо, но обратите внимание на кое-что здесь: я написал метод для взятия List<double>
, который является классом с гораздо большей функциональностью, чем этот код, зависит от . Где он использует Insert
? Где он использует RemoveAt
? FindAll
? Sort
? Нет, ничего из этого не требуется. Так действительно ли необходимо , чтобы этот метод получил List<double>
?
Более того, скажем, у меня есть double[]
. Теоретически, я должен иметь возможность ввести это право в качестве параметра values
, так как все, что я делаю, это перечисляю его, используя foreach
; но так как я набрал values
как List<double>
, чтобы передать double[]
моему Sum
методу, я должен сделать это:
double sum = Sum(new List<double>(myArray));
Это просто совершенно ненужный новый объект, который я построил просто для вызова кода, который действительно должен был бы быть в состоянии обработать мой исходный объект.
Путем написания методов, которые принимают интерфейсы в качестве параметров, вы делаете свой код более гибким и более мощным, и вы избегаете наложения неуместных ограничений ( дает мне X, хотя я мог бы так же легко сделать это с Y ) на код вызова.