#c# #generics #abstract-class #abstraction
#c# #обобщения #абстрактный класс #абстракция
Вопрос:
Вот краткий пример проблемы, с которой я сталкиваюсь
У меня есть два абстрактных класса EntityAbs и ListEntityAbs :
public abstract class EntityAbs {
//Save itself in a Database
public abstract int SaveEntity();
}
public abstract class ListEntitiesAbs<T> where T : EntityAbs {
protected List<T> InnerList;
//Save each values in a Database
public virtual int SaveEntities()
{
return InnerList.Sum(entity => entity.SaveEntity());
}
}
Несколько классов, которые наследуют EntityAbs и получают свои собственные ListEntities (пример с классом с именем Item) :
public class Item : EntityAbs {
public override int SaveEntity()
{
// Implements here how I save it
}
}
public class Items : ListEntitiesAbs<Item>, IList<Item> {
// Has specific class stuff in it
}
Теперь я хотел бы сохранить все ListEntitiesAbs где-нибудь еще в моей базе данных
public int Save(params ListEntitiesAbs<EntityAbs>[] lists)
{
for(int i = 0; i < lists.Length; i )
lists[i].SaveEntities();
}
Items items = new Items();
// add items
int result = Save(items);
Но тогда элементы (или любой другой список, который я добавляю сюда) отображают ошибку Visual Studio, и я не понимаю, почему.
Ошибка говорит, что это Cannot convert from Items to ListEntitiesAbs<EntityAbs>
, но элементы наследуются из ListEntitiesAbs и Item из EntityAbs..
Я что-то упускаю? Я пробовал использовать ListEntityAbs или использовать Cast<>, но ничего не подходит
Любая помощь приветствуется, поскольку я даже не уверен, действительно ли такое поведение возможно
Ответ №1:
Well ListEntitiesAbs<T>
не является ковариантным. Это означает, что ListEntitiesAbs<Item>
это не так и не может быть тривиально преобразовано в, ListEntitiesAbs<EntityAbs>
.
Вариант 1: сделать Save
общий
public int Save<T>(params ListEntitiesAbs<T>[] lists) where T:EntityAbs
{
for(int i = 0; i < lists.Length; i )
lists[i].SaveEntities();
}
Вариант 2: не универсальный интерфейс. Вы также могли бы создать ковариантный интерфейс, но, похоже, в данном конкретном случае это не требуется.
public interface IListEntitiesAbs {
public int SaveEntities();
}
public int Save(params IListEntitiesAbs[] lists){
...
}
Комментарии:
1. Вариант 1 — это именно то, что мне было нужно, и мне стыдно, что я не подумал об этом. Это решает мою проблему совместимости, но,
params
похоже, не работает, если я добавляю несколько списков при вызовеSave()
метода, у вас есть какие-либо другие подсказки?2. @arrcival
params
должен отлично работать с универсальными методами. Можно предположить, что типы не совпадают, т. Е. Вы пытаетесь вызватьSave(new ListEntitiesAbs<Item>(), new ListEntitiesAbs<EntityAbs>())
это, но это не сработает по причине, указанной выше. Если это проблема, используйте вместо этого вариант 2.3. Это скрипка .NET, основанная на моем примере dotnetfiddle.net/eqPglu . Я думаю, ни одно из этих решений не работает, и мне придется выбрать вариант 2