Я столкнулся с подобными ситуациями и хочу дать более конкретный пример того, почему это недопустимо. Общие части моего приложения связаны с интерфейсом, который содержит свойства, и предоставляет данные через этот интерфейс в другую часть приложения, содержащую конкретные классы, реализующие эти интерфейсы.
Цель, я думаю, похожа на вашу: классы-классы, чтобы иметь больше функциональности, а интерфейс обеспечивает абсолютный минимум, необходимый для общей части приложения. Для интерфейса очень полезно выявить наименьшее количество функциональных возможностей, поскольку оно максимизирует совместимость / повторное использование. То есть он не требует, чтобы исполнитель интерфейса реализовал больше, чем это необходимо.
Однако учтите, был ли у вас наборщик по этому свойству. Вы создаете экземпляр вашего конкретного класса и передаете его некоторому универсальному помощнику, который принимает ISomeData. В коде этого помощника они работают с ISomeData. Без какого-либо типа T, где T: new () или заводской шаблон, они не могут создавать новые экземпляры для ввода данных, которые соответствуют вашей конкретной реализации. Они просто возвращают список, который реализует IEnumerable:
instanceISomeData.Data = new SomeOtherTypeImplementingIEnumerable ();
Если SomeOtherTypeImplementingIEnumerable не наследует List, но вы реализовали .Data как список , то это недопустимое присвоение. Если компилятор разрешил вам это сделать, тогда сценарии, подобные этому, будут повреждены во время выполнения, потому что SomeOtherTypeImplementingIEnumerable не может быть передан в List. Однако в контексте этого помощника, работающего с ISomeData, он все равно не нарушал интерфейс ISomeData, и назначение любого типа, поддерживающего IEnumerable, должно быть действительным. Таким образом, ваша реализация, если бы компилятор допустил это, мог нарушить превосходный код, работающий с интерфейсом.
Вот почему вы не можете реализовать .Data как производный тип. Вы более жестко ограничиваете реализацию .Data только за исключением List, а не любого IEnumerable. Таким образом, хотя интерфейс говорит, что «любой IEnumerable разрешен», ваша конкретная реализация заставит ранее существовавший код, поддерживающий ISomeData, внезапно сломаться при работе с вашей реализацией интерфейса.
Конечно, вы действительно не запускаете в этот сценарий только с помощью геттера, но это усложнит ситуацию, чтобы разрешить его в сценариях получения, но не иначе.
Обычно я использую решение Джейка или решение Алиото, в зависимости от того, насколько я себя чувствую в настоящий момент .