У меня была та же проблема, что и у вас, и я нахожу объяснение "контракта" немного запутанным.
Если вы укажете, что метод принимает интерфейс IEnumerable в качестве входного параметра, вы можете сказать, что это контракт, указывающий, что параметр должен иметь тип, который наследуется от интерфейса IEnumerable, и, следовательно, поддерживает все методы, указанные в IEnumerable. интерфейс. То же самое было бы верно, если бы мы использовали абстрактный класс или нормальный класс. Любой объект, который наследуется от этих классов, будет приемлем для передачи в качестве параметра. В любом случае вы могли бы сказать, что унаследованный объект поддерживает все открытые методы базового класса, будь то базовый класс, нормальный класс, абстрактный класс или интерфейс.
Абстрактный класс со всеми абстрактными методами в основном такой же, как интерфейс, так что вы можете сказать, что интерфейс - это просто класс без реализованных методов. Вы можете фактически удалить интерфейсы из языка и просто использовать абстрактный класс только с абстрактными методами. Я думаю, что причина, по которой мы их разделяем, заключается в семантических причинах, но по причинам кодирования я не вижу причины и нахожу ее просто запутанной.
Другим предложением может быть переименование интерфейса в интерфейсный класс, так как интерфейс - это просто еще один вариант класса.
В некоторых языках есть тонкие различия, которые позволяют классу наследовать только 1 класс, но несколько интерфейсов, в то время как в других вы можете иметь много обоих, но это другая проблема, и я не думаю, что она имеет прямое отношение