Компилятор требует от вас реализации всех виртуальных машин, поскольку он не может знать, какие из них будут вызваны, когда какая-то непредвиденная сборка загрузит вашу сборку в какой-то момент в неизвестном будущем.Унаследовав от интерфейса, вы «подписываете договор», который обещает, что вы будете реализовывать всех его участников.Компилятор поддерживает вас в этом соглашении, так что другие сборки смогут положиться на него.
Цель функции интерфейса - дать возможность вашему классу сообщать любой другой сборке, в любом месте, в любое время, «это то, что вы можете попросить меня сделать».Если вы хотите объявить о меньшей возможности, определите новый интерфейс, который предоставляет только те функции, которые вам нужны, и используйте его вместо этого.
Конечно, все это вещи промышленного уровня.Это больше, чем вам нужно для вашего кода прямо сейчас.Но C # предназначен для того, чтобы делать серьезные вещи, а не только игрушки.
Что касается двух разных, почти идентичных переопределений: вы должны переопределить оба свойства Current, потому что они существенно различаются: один - это универсальный возвращающий T;другой не является универсальным возвращающим объектом.Вы всегда можете рассматривать ссылку String как ссылку на Object, но это не идет в обе стороны.А как насчет типов значений?T не обязан быть классом.Несомненно, компилятор мог бы гипотетически выяснить все это для вас и позволить вам сорваться с крючка в тех случаях, когда оба они взаимозаменяемы, но это не так, и я не уверен, что это должно быть.Если вы хотите C ++, вы знаете, где его найти.