Так сложилось, что я сначала писал на С++, затем несколько лет на Java, теперь, вот, не оставляя Java, необходимо писать на C#. Возможно это поможет определить причины возникновения описанной ситуации.
Вопрос в следующем: имеется интерфейсы IThingManager и IThing. Первый — описание некоего управляющего вещью, второе — описание вещи:
public interface IThingManager
{
IThing getAll();
void add(IThing thing);
}
public interface IThing
{
String name;
}
Ещё есть класс Thing, имплементирующий IThing:
public class Thing : IThing
{
}
Далее, имеется интерфейс ICarManager, наследующий IThingManager, а так же класс Car, наследующий Thing:
public interface ICarManager : IThingManager
{
Car getAll();
void add(IThing thing);
}
public class Car : Thing
{
String color;
int cost;
}
И последнее: есть класс CarManager, имплементирующий ICarManager:
public class CarManager : ICarManager
{
Car getAll() {};
void add(IThing thing) {};
}
Итак, имея всё вышеописанное, компилятор сообщает мне о том, что в интерфейсе ICarManager методом "Car getAll()" я скрываю(я так понял, что переопределяю) метод интерфейса IThingManager "IThing getAll()" и предлагает мне в случае намеренности этого поставить "new" в интерфейсе IThingManager. После того, как я это делаю, компилятор ругается, что класс CarManager не реализует необходимый метод интерфейса IThingManager "IThing getAll()".
Вопрос: как такое может быть, если один и тот же компилятор говорит мне, что я СКРЫВАЮ этот метод, а потом я его НЕ реализовываю? Противоречие?
В Java такой код ошибок не вызывает, поэтому я решил повторить его и в C#, но безуспешно, почему?
Заранее спасибо!
-= J-Pro =- with respect
Re: Наследование и переопределение методов - где ошибка?
Здравствуйте, J-Pro, Вы писали:
JP>Вопрос: как такое может быть, если один и тот же компилятор говорит мне, что я СКРЫВАЮ этот метод, а потом я его НЕ реализовываю? Противоречие? JP>В Java такой код ошибок не вызывает, поэтому я решил повторить его и в C#, но безуспешно, почему?
Смотрите в спецификации 13.4.1 Explicit interface member implementations
Re: Наследование и переопределение методов - где ошибка?
JP>public interface IThingManager
JP>{
JP> IThing getAll();
JP> void add(IThing thing);
JP>}
JP>Далее, имеется интерфейс ICarManager, наследующий IThingManager, а так же класс Car, наследующий Thing:
JP>[c#]
JP>public interface ICarManager : IThingManager
JP>{
JP> Car getAll();
JP> void add(IThing thing);
JP>}
JP>И последнее: есть класс CarManager, имплементирующий ICarManager:
JP>[c#]
JP>public class CarManager : ICarManager
JP>{
JP> Car getAll() {};
JP> void add(IThing thing) {};
JP>}
JP>
JP>Итак, имея всё вышеописанное, компилятор сообщает мне о том, что в интерфейсе ICarManager методом "Car getAll()" я скрываю(я так понял, что переопределяю) метод интерфейса IThingManager "IThing getAll()" и предлагает мне в случае намеренности этого поставить "new" в интерфейсе IThingManager. После того, как я это делаю, компилятор ругается, что класс CarManager не реализует необходимый метод интерфейса IThingManager "IThing getAll()".
JP>Вопрос: как такое может быть, если один и тот же компилятор говорит мне, что я СКРЫВАЮ этот метод, а потом я его НЕ реализовываю? Противоречие? JP>В Java такой код ошибок не вызывает, поэтому я решил повторить его и в C#, но безуспешно, почему?
в IThingManager должен быть определен метод IThing getAll();
в ICarManager Car getAll()
т.е. два метода с одинаковым названием, но разными возвращаемыми типами. Тут нужно реализовать оба метода и указать в одном из них явную принадлежность к интерфейсу, например так:
public class CarManager : ICarManager
{
Car getAll(){return null;}
IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
...
}
Сражение выигрывает тот, кто твердо решил его выиграть
(с) Л.Н. Толстой
Re: Наследование и переопределение методов - где ошибка?
Здравствуйте, J-Pro, Вы писали: JP>Итак, имея всё вышеописанное, компилятор сообщает мне о том, что в интерфейсе ICarManager методом "Car getAll()" я скрываю(я так понял, что переопределяю) метод интерфейса IThingManager "IThing getAll()" и предлагает мне в случае намеренности этого поставить "new" в интерфейсе IThingManager. После того, как я это делаю, компилятор ругается, что класс CarManager не реализует необходимый метод интерфейса IThingManager "IThing getAll()".
Сигнатура методов не включает в себя возвращаемое значение, поэтому действительно у Вас имена совпадают, нужен new:
public interface ICarManager : IThingManager
{
new Car GetAll();
new void Add(IThing thing);
}
Теперь ICarManager включает 4 метода, которые необходимо заимплементить, например так:
public class CarManager : ICarManager
{
public Car GetAll() { ... }
public void Add(IThing thing) { ... }
IThing IThingManager.GetAll() { ... }
void IThingManager.Add(IThing thing) { ... }
}
Члены ICarManager реализованы неявно, а члены "унаследованного" IThingManager — явно (explicit interface implementation)...
Re[2]: Наследование и переопределение методов - где ошибка?
NC>public class CarManager : ICarManager
NC>{
NC> Car getAll(){return null;}
NC> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
NC> ...
NC>}
NC>
public class CarManager : ICarManager
{
public Car getAll(){return null;}
IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который еделен без принадлежности к интерфейсам*/}
...
}
Сражение выигрывает тот, кто твердо решил его выиграть
(с) Л.Н. Толстой
Re[2]: Наследование и переопределение методов - где ошибка?
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, J-Pro, Вы писали:
JP>>Далее, имеется интерфейс ICarManager, наследующий IThingManager, а так же класс Car, наследующий Thing: _FR>
NC>>public class CarManager : ICarManager
NC>>{
NC>> Car getAll(){return null;}
NC>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
NC>> ...
NC>>}
NC>>
NC>
NC>public class CarManager : ICarManager
NC>{
NC> public Car getAll(){return null;}
NC> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который еделен без принадлежности к интерфейсам*/}
NC> ...
NC>}
NC>
Спасибо за ответ. Это действительно решение.
Честно говоря, думал, что С# сам понимает, что у меня IThing — базовый инерфейс для Car и не попросит реализовывать метод IThing getAll()... Понимаете, о чём я? Т.е. это не просто ДРУГОЙ возвращаемый тип. Это, фактически, тот же тип, раз он унаследован от IThing....
-= J-Pro =- with respect
Re[3]: Наследование и переопределение методов - где ошибка?
NC>>public class CarManager : ICarManager
NC>>{
NC>> Car getAll(){return null;}
NC>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
NC>> ...
NC>>}
NC>>
NC>
NC>public class CarManager : ICarManager
NC>{
NC> public Car getAll(){return null;}
NC> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который еделен без принадлежности к интерфейсам*/}
NC> ...
NC>}
NC>
Только что попробовал. Результат: "Cannot implicitly convert type 'System.Collections.Generic.List<Car>' to 'System.Collections.Generic.List<IThing>'... Мне нужен именно список...
-= J-Pro =- with respect
Re[4]: Наследование и переопределение методов - где ошибка?
Здравствуйте, J-Pro, Вы писали:
JP>Здравствуйте, NovaCxarmulo, Вы писали:
NC>>>
NC>>>public class CarManager : ICarManager
NC>>>{
NC>>> Car getAll(){return null;}
NC>>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
NC>>> ...
NC>>>}
NC>>>
NC>>
NC>>public class CarManager : ICarManager
NC>>{
NC>> public Car getAll(){return null;}
NC>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который еделен без принадлежности к интерфейсам*/}
NC>> ...
NC>>}
NC>>
JP>Только что попробовал. Результат: "Cannot implicitly convert type 'System.Collections.Generic.List<Car>' to 'System.Collections.Generic.List<IThing>'... Мне нужен именно список...
Угу, мне тоже не нравится что возврат унаследованных типов не принимается как реализация интерфейса, хотя непонятно почему.
Список нужно возвращать того типа, который требуется, т.е.
List<Car> cars = getAll();
List<IThing> res = new List<IThing>(car.Length);
for(int i = 0; i < cars.Length; ++i)
res[i] = cars[i];
или что-то подобное.
Сражение выигрывает тот, кто твердо решил его выиграть
(с) Л.Н. Толстой
Re[4]: Наследование и переопределение методов - где ошибка?
От:
Аноним
Дата:
28.05.09 08:09
Оценка:
Здравствуйте, J-Pro, Вы писали:
JP>Здравствуйте, NovaCxarmulo, Вы писали:
NC>>>
NC>>>public class CarManager : ICarManager
NC>>>{
NC>>> Car getAll(){return null;}
NC>>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
NC>>> ...
NC>>>}
NC>>>
NC>>
NC>>public class CarManager : ICarManager
NC>>{
NC>> public Car getAll(){return null;}
NC>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который еделен без принадлежности к интерфейсам*/}
NC>> ...
NC>>}
NC>>
JP>Только что попробовал. Результат: "Cannot implicitly convert type 'System.Collections.Generic.List<Car>' to 'System.Collections.Generic.List<IThing>'... Мне нужен именно список...
Это называется ковариантность возвращаемых значений. (covariance of return type) — хотя в точности определния я могу и ошибатся.
В Яве такая возможность есть в C# к сожалению нету (Опять же в самом CLR это есть, а вот компилятор C# на это ругается, в С# 4,0 появится ковариантность generic'ов)
Но в C# есть ковариантность массивов. Т.е.
Car[] cars = new Car[..];
Можно преобразовать к IList<IThing>.
IList<IThing> things = cars;
Я обходился этим решением, т.е. либо всегда использовал массивы и их возвращал как IList<Базовый тип>
Либо вызывал у колекции ToArray(), а потом уже возвращал.
Re: Наследование и переопределение методов - где ошибка?
public interface IThing
{
String Name { get; }
}
public interface IThingManager
{
IThing GetAll();
void Add(IThing thing);
}
public interface IThingManager<TThing> : IThingManager
where TThing : IThing
{
new TThing GetAll();
void Add(TThing thing);
}
public abstract class Thing : IThing
{
public abstract string Name { get; }
}
public abstract class ThingManager<TThing> : IThingManager<TThing>
where TThing : Thing
{
public abstract TThing GetAll();
public abstract void Add(TThing thing);
IThing IThingManager.GetAll() { return GetAll(); }
void IThingManager.Add(IThing thing) { Add((TThing)thing); }
}
public class Car : Thing
{
String color;
int cost;
public override string Name { get { throw new NotImplementedException(); } }
}
public class CarManager : ThingManager<Car>
{
public override Car GetAll() { throw new NotImplementedException(); }
public override void Add(Car thing) { throw new NotImplementedException(); }
}
(Некоторые классы/интерфейсы могут быть лишними, или еще нужно добавить — зависит от специфики задач.)
Re[2]: Наследование и переопределение методов - где ошибка?
Здравствуйте, Ravlyk, Вы писали:
R>Не совсем ответ на вопрос... R>Используйте generic:
R>
R>public interface IThing
R>{
R> String Name { get; }
R>}
R>public interface IThingManager
R>{
R> IThing GetAll();
R> void Add(IThing thing);
R>}
R>public interface IThingManager<TThing> : IThingManager
R> where TThing : IThing
R>{
R> new TThing GetAll();
R> void Add(TThing thing);
R>}
R>public abstract class Thing : IThing
R>{
R> public abstract string Name { get; }
R>}
R>public abstract class ThingManager<TThing> : IThingManager<TThing>
R> where TThing : Thing
R>{
R> public abstract TThing GetAll();
R> public abstract void Add(TThing thing);
R> IThing IThingManager.GetAll() { return GetAll(); }
R> void IThingManager.Add(IThing thing) { Add((TThing)thing); }
R>}
R>public class Car : Thing
R>{
R> String color;
R> int cost;
R> public override string Name { get { throw new NotImplementedException(); } }
R>}
R>public class CarManager : ThingManager<Car>
R>{
R> public override Car GetAll() { throw new NotImplementedException(); }
R> public override void Add(Car thing) { throw new NotImplementedException(); }
R>}
R>
R>(Некоторые классы/интерфейсы могут быть лишними, или еще нужно добавить — зависит от специфики задач.)
Спасибо. Так я и сделал вчера по совету своего коллеги. Но этот подход, ессно, не позволяет мне получить объект класса CarManager в виде самого базового интерфейса IThingManager. Только я делал так:
public interface IThingManager<T>
{
T getAll();
void add(T thing);
}
public interface ICarManager : IThingManager<Car>
{
Car getAll();
void add(Car thing);
}
public class CarManager : ICarManager
{
Car getAll() {};
void add(Car thing) {};
}
И всё же было бы приятно видеть ковариантность возвращаемых значений и в C#, я бы несомненно ею воспользовался.
Спасибо за ответ.
-= J-Pro =- with respect
Re[5]: Наследование и переопределение методов - где ошибка?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, J-Pro, Вы писали:
JP>>Здравствуйте, NovaCxarmulo, Вы писали:
NC>>>>
NC>>>>public class CarManager : ICarManager
NC>>>>{
NC>>>> Car getAll(){return null;}
NC>>>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который определен без принадлежности к интерфейсам*/}
NC>>>> ...
NC>>>>}
NC>>>>
NC>>>
NC>>>public class CarManager : ICarManager
NC>>>{
NC>>> public Car getAll(){return null;}
NC>>> IThing IThingManager.getAll() {return getAll();/*Тут будет вызываться getAll который еделен без принадлежности к интерфейсам*/}
NC>>> ...
NC>>>}
NC>>>
JP>>Только что попробовал. Результат: "Cannot implicitly convert type 'System.Collections.Generic.List<Car>' to 'System.Collections.Generic.List<IThing>'... Мне нужен именно список...
А>Это называется ковариантность возвращаемых значений. (covariance of return type) — хотя в точности определния я могу и ошибатся. А>В Яве такая возможность есть в C# к сожалению нету (Опять же в самом CLR это есть, а вот компилятор C# на это ругается, в С# 4,0 появится ковариантность generic'ов)
А>Но в C# есть ковариантность массивов. Т.е.
А>Car[] cars = new Car[..];
А>Можно преобразовать к IList<IThing>.
А>IList<IThing> things = cars;
А>Я обходился этим решением, т.е. либо всегда использовал массивы и их возвращал как IList<Базовый тип> А>Либо вызывал у колекции ToArray(), а потом уже возвращал.
Хм... если в CLR это есть, то могу ли я это использовать в J#?
Спасибо Вам за ответ и совет со списком, попробую.
-= J-Pro =- with respect
Re[3]: Наследование и переопределение методов - где ошибка?
Здравствуйте, J-Pro, Вы писали:
JP>Спасибо. Так я и сделал вчера по совету своего коллеги. Но этот подход, ессно, не позволяет мне получить объект класса CarManager в виде самого базового интерфейса IThingManager.
Почему не позволяет?
CarManager наследуется от ThingManager<TThing>, который имплементирует IThingManager<TThing>, который наследуется от IThingManager. И в TThingManager<TThing> реализованы нетипизированные методы GetAll() и Add().
Все должно работать (но я не проверял).
Re: Наследование и переопределение методов - где ошибка?
Здравствуйте, J-Pro, Вы писали:
JP>В Java такой код ошибок не вызывает, поэтому я решил повторить его и в C#, но безуспешно, почему?
В C#, в отличие от Java, нельзя уточнять тип возвращаемого значения у override методов. Кроме того, методы производных интерфейсов никогда не считаются override для методов базовых интерфейсов.