【问题标题】:How do I define the return type of an interface method to be another interface?如何将接口方法的返回类型定义为另一个接口?
【发布时间】:2009-03-16 14:29:28
【问题描述】:

我是接口和抽象类的新手。我想创建几个接口来为购物车系统的对象定义核心方法和变量。然后我想创建实现核心功能的抽象类。这个想法是,它们可以被其他类以稍微不同的方式用于不同的项目。

这是我的(精简)界面:

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

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

这是我实现 ICart 的抽象 Cart 类(同样,只显示相关行):

public abstract class Cart : ICart
{

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

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

还有我实现 ICartItem 的 CartItem 类:

public abstract class CartItem : ICartItem
{
    ...
}

当我尝试编译类时,我收到一条错误消息:“Cart”没有实现接口成员“CartItems”。 “Cart.CartItems”无法实现“ICart.CartItems”,因为它没有 System.Collections.Generic.List 的匹配返回类型。

我认为这里的想法是接口可以由许多类实现,这些类以不同的方式执行核心功能并添加新方法等。为什么我的接口需要知道实际使用的是什么类,只要该类实际上正确实现了接口?

【问题讨论】:

    标签: c# interface


    【解决方案1】:

    您需要在 C# 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; }
    }
    

    【讨论】:

    • 泛型从 c# 2.0 开始可用 :)
    • @Marc Gravell:是的,我所说的 C# 3 的意思是它还没有提供协方差。有趣的是,当我决定不提及这个问题时,我的想法正是你,因为我担心你会突然出现并教我 C# 4 协方差仅适用于只读集合
    • @DrJokepu 你拯救了这一天!
    【解决方案2】:

    在您的抽象类中,您应该定义 CartItems 属性的返回类型为 List&lt;ICartItem&gt; 类型。

    但是,如果您真的希望该属性是 List&lt;CartItem&gt; 类型,您可以这样做:

    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)建议不要在公共界面中公开 List。 List 是一个实现细节 - IList 是适当的接口/返回类型。

      【讨论】:

        【解决方案4】:

        接口是一种协议。如果你愿意,你和任何使用你的班级的人之间的合同。通过告诉人们您正在实现 ICart 接口,您向他们保证接口中的所有方法都存在于您的类中。因此,您的所有方法都必须与接口方法的签名相匹配。

        为了返回实现 ICartItem 的项目列表,您需要按照 DrJokepu 的建议使用泛型。这告诉大家,该接口只提供了一个实现 ICartItem 的对象列表,而不是具体的 ICartItem。

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

        【讨论】:

          【解决方案5】:

          ICart 为 CartItems 指定了一个 getter 和 setter,但您的实现只有一个 get。

          【讨论】:

            【解决方案6】:

            有两种方法可以做到这一点。您可以使用泛型或显式实现接口成员。

            泛型

            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
            {
                ...
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-05-16
              • 2020-09-04
              • 2014-12-09
              • 1970-01-01
              • 1970-01-01
              • 2012-08-08
              • 1970-01-01
              相关资源
              最近更新 更多