Следующий код:"Интерфейс не реализован" Возвращая производный тип
public interface ISomeData
{
IEnumerable<string> Data { get; }
}
public class MyData : ISomeData
{
private List<string> m_MyData = new List<string>();
public List<string> Data { get { return m_MyData; } }
}
Выдает следующую ошибку:
error CS0738: 'InheritanceTest.MyData' does not implement interface member 'InheritanceTest.ISomeData.Data'. 'InheritanceTest.MyData.Data' cannot implement 'InheritanceTest.ISomeData.Data' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable'.
Поскольку список <T> реализует IEnumerable <T>, можно было бы подумать что мой класс будет реализовывать интерфейс. Может ли кто-нибудь объяснить, что такое обоснование для этого не компиляции?
Как я могу видеть это, есть два возможных решения:
- Изменение интерфейса, чтобы быть более конкретным и требуют IList быть реализованы.
- Измените мой класс (MyData), чтобы вернуть IEnumerable и реализовать оригинальный интерфейс.
Теперь предположим, что у меня есть следующий код:
public class ConsumerA
{
static void IterateOverCollection(ISomeData data)
{
foreach (string prop in data.MyData)
{
/*do stuff*/
}
}
}
public class ConsumerB
{
static void RandomAccess(MyData data)
{
data.Data[1] = "this line is invalid if MyPropList return an IEnumerable<string>";
}
}
Я мог бы изменить свой интерфейс, чтобы требовать IList быть реализован (вариант 1), но ограничения, которые могут реализовать интерфейс и количество классы, которые могут быть переданы в ConsumerA. Или я мог бы изменить реализацию (класс MyData), чтобы он возвращал IEnumerable вместо List (вариант 2), но затем ConsumerB пришлось бы переписать.
Это, кажется, недостаток C#, если кто-то не может просветить меня.
..Это не является недостатком, просто еще один пример C#, просто делающий то, что вы ему рассказываете. У VB.NET есть много маленьких ситуаций, подобных этому (неуверенный об этом конкретном, хотя), где они компилятор скажет: «Я знаю, что вы действительно хотите», и не будет пытаться выправить его; C# скажет: «Мне все равно, чего вы хотите, все, что я знаю, это то, что вы говорите мне, не летает». – STW
Я до сих пор не согласен и думаю, что это недостаток. Интерфейс говорит, что «вы должны предоставить данные, которые могут быть перечислены», и мой класс, в котором говорится: «Вот данные, которые вы можете перечислить и сделать произвольный доступ к И и т. Д. И т. Д.». Однако компилятор говорит: «Вы не выполняете контракт!». – Daniel
@ Daniel, но если интерфейс указывает только, что вы предоставляете данные, которые могут быть перечислены, то он никогда не позволит вызывающему пользователю воспользоваться всеми другими функциями. Ограничив вас, чтобы выставляли * просто * объект, совместимый с IEnumerable, он заставляет вас осознанно осознавать, что любое другое добавление значений List ** никогда не будет когда-либо когда-либо когда-либо доступным для вызывающего. Это делает вас совестью. Это мешает вам завтра приходить и спрашивать: «MyData.Data предоставляет список, но когда потребительский класс работает с ним, я не могу позвонить .Add()! WTC! C# stoopid!» –
STW