Подтвердить что ты не робот

Как определить тип возврата метода интерфейса в качестве другого интерфейса?

Я новичок в интерфейсах и абстрактных классах. Я хочу создать пару интерфейсов для определения основных методов и переменных для объектов для системы корзины покупок. Затем я хочу создать абстрактные классы, которые реализуют основные функции. Идея состоит в том, что они могут использоваться другими классами несколько разными способами для разных проектов.

Вот мои (вырезанные) интерфейсы:

public interface ICart
{
    ...
    List<ICartItem> CartItems { get; set; }
}

public interface ICartItem
{
    int ProductId { get; set; }
    int Quantity { get; set; }
}

И вот мой абстрактный класс Cart (опять же, только показывающий соответствующие строки), который реализует ICart:

public abstract class Cart : ICart
{

    private List<CartItem> _cartItems = new List<CartItem>();

    public List<CartItem> CartItems 
    {
        get
        {
            return _cartItems;
        }
    }
}

И мой класс CartItem, который реализует ICartItem:

public abstract class CartItem : ICartItem
{
    ...
}

Когда я пытаюсь скомпилировать классы, я получаю сообщение об ошибке: "Корзина" не реализует интерфейс "CartItems". "Cart.CartItems" не может реализовать "ICart.CartItems", потому что у него нет соответствующего типа возврата System.Collections.Generic.List <ICartItem> .

Я думал, что идея здесь заключается в том, что интерфейс может быть реализован рядом классов, которые выполняют основные функции по-разному и добавляют новые методы и т.д. Почему мой интерфейс должен знать, какой класс фактически используется, до тех пор, пока этот класс действительно реализует интерфейс правильно?

4b9b3361

Ответ 1

Для достижения этой цели вам необходимо предоставить общие родословные в С# 2:

public interface ICart<T> where T : ICartItem
{
    // ...
    List<T> CartItems { get; set; }
}

public abstract class Cart : ICart<CartItem>
{
    // ...
    public List<CartItem> CartItems { get; set; }
}

Ответ 2

В вашем абстрактном классе вы должны определить, что возвращаемый тип свойства CartItems имеет тип List<ICartItem>.

Но если вы действительно хотите, чтобы свойство имело тип List<CartItem>, вы можете сделать это:

public interface ICart<TCartItem> where TCartItem : ICartItem
{
   List<TCartItem> CartItems { get; set; }
}

public interface ICartItem
{
}

public abstract class Cart : ICart<CartItem>
{
     public List<CartItem> { get; set; }
}

public abstract class CartItem : ICartItem
{
}

Ответ 3

Это вопрос противоположности/ковариации.

Для компиляции требуется 2 изменения.

1) Удалите опцию "set" в свойстве интерфейса. (Он реализует только свойство get, которое в любом случае имеет смысл)

2) Измените корзину на:


public abstract class Cart : ICart
{
private List<CartItem> _cartItems = new List<CartItem>();

public List<ICartItem> CartItems 
{ ...

код >

Я также настоятельно рекомендую изменить свой интерфейс, чтобы показывать IList вместо List. Руководства по проектированию (и FxCop) рекомендуют не показывать список в открытом интерфейсе. Список представляет собой деталь реализации - IList - соответствующий тип интерфейса/возврата.

Ответ 4

Интерфейс - это соглашение. Контракт, если хотите, между вами и любым, кто использует ваш класс. Сообщая людям, что вы реализуете интерфейс ICart, вы обещаете им, что все методы в интерфейсе существуют в вашем классе. Таким образом, все ваши методы должны соответствовать сигнатурам методов интерфейса.

Чтобы вернуть список элементов, реализующих ICartItem, вам нужно использовать дженерики, как было предложено DrJokepu. Это говорит всем, что интерфейс только gurentees список объектов, которые реализуют ICartItem, а не ICartItem конкретно.

public interface ICart<T> where T : ICartItem
{
    List<T> CartItems { get; set; }
}

Ответ 5

ICart указывает получателя и сеттер для CartItems, но ваша реализация имеет только get.

Ответ 6

Есть два способа сделать это. Вы можете использовать generics или явно реализовать элементы интерфейса.

Непатентованные

public interface ICart<TCartItem> where TCartItem : ICartItem
{
    ...
    List<TCartItem> CartItems { get; set; }
}

public interface ICartItem
{
    int ProductId { get; set; }
    int Quantity { get; set; }
}

public abstract class Cart : ICart<CartItem>
{

    private List<CartItem> _cartItems = new List<CartItem>();

    public List<CartItem> CartItems 
    {
        get
        {
            return _cartItems;
        }
    }
}
public abstract class CartItem : ICartItem
{
    ...
}

Явно реализованные члены

public interface ICart
{
    ...
    List<ICartItem> CartItems { get; set; }
}
public interface ICartItem
{
    int ProductId { get; set; }
    int Quantity { get; set; }
}

public abstract class Cart : ICart
{
    private List<CartItem> _cartItems = new List<CartItem>();

    List<ICartItem> ICart.CartItems
    {
       get
       {
           return CartItems;
       }
    }
    public List<CartItem> CartItems 
    {
        get
        {
            return _cartItems;
        }
    }
}
public abstract class CartItem : ICartItem
{
    ...
}