C#接口和泛型列表

3

我有一个被定义为:

namespace RivWorks.Interfaces.DataContracts
{
    public interface IProduct
    {
        [XmlElement]
        [DataMember(Name = "ID", Order = 0)]
        Guid ProductID { get; set; }
        [XmlElement]
        [DataMember(Name = "altID", Order = 1)]
        long alternateProductID { get; set; }
        [XmlElement]
        [DataMember(Name = "CompanyId", Order = 2)]
        Guid CompanyId { get; set; }
        ...
        [XmlElement]
        [DataMember(Name = "buttonPositionCSS", Order = 14)]
        string buttonPositionCSS { get; set; }
    }
}

我有一个具体的实现,如下:

namespace RivWorks.Model.Objects
{
    [DataContract(Name = "Product", Namespace = "http://rivworks.com/DataContracts/2009/01/15")]
    public class Product : IProduct
    {
        #region Declarations
        private Guid _productID;
        private long _altProductID;
        private Guid _companyId;
        ...
        private string _buttonPositionCSS;
        #endregion

        #region IProduct Members
        public Guid ProductID { get { return _productID; } set { _productID = value; } }
        public long alternateProductID { get { return _altProductID; } set { _altProductID = value; } }
        public Guid CompanyId { get { return _companyId; } set { _companyId = value; } }
        ...
        public string buttonPositionCSS { get { return _buttonPositionCSS; } set { _buttonPositionCSS = value; } }
        #endregion
    }
}

我有另一个接口的定义如下:

namespace RivWorks.Interfaces.Services
{
    public interface IProductManager
    {
        #region Products
        IProduct GetProductById(Guid productId);
        List<IProduct> GetProductByCompany(Guid companyId);
        int SaveProduct(IProduct product);
        int DeleteProduct(Guid productId);
        #endregion
    }
}

我有一个定义为:

namespace RivWorks.Controller
{
    public class ProductManager : IProductManager
    {
        #region Declare Models
        private static RivWorks.Model.Negotiation.RIV_Entities _dbRiv = RivWorks.Model.Stores.RivEntities(AppSettings.RivWorkEntities_connString);
        private static RivWorks.Model.NegotiationAutos.RivFeedsEntities _dbFeed = RivWorks.Model.Stores.FeedEntities(AppSettings.FeedAutosEntities_connString);
        #endregion

        #region Products
        public IProduct GetProductById(Guid productId)
        {
            // deleted for simplicity sake
            return product;
        }
        public List<IProduct> GetProductByCompany(Guid companyId)
        {
            var company = (from a in _dbRiv.Company where a.CompanyId == companyId select a).First();
            var companyDetails = from a in _dbRiv.AutoNegotiationDetails where a.CompanyId == companyId select a;
            // ################################################## //
            List<IProduct> productList = new List<RivWorks.Model.Objects.Product>();
            // ################################################## //
            // deleted for simplicity sake
            return productList;
        }
        public int SaveProduct(IProduct product)
        {
            return 0;  // stub
        }
        public int DeleteProduct(Guid productId)
        {
            return 0;  // stub
        }
        #endregion
    }
}

我在编译时遇到了以下错误:

无法隐式转换类型 'System.Collections.Generic.List<RivWorks.Model.Objects.Product>' 为 'System.Collections.Generic.List<RivWorks.Interfaces.DataContracts.IProduct>'

该系统是一个非常服务化的系统(WCF, WebOrb等),我想将接口暴露作为我的契约。 我在.NET中使用模型和控制器,并使用服务作为视图(代理)来提供给第三方消费者(真正的视图)。
我缺少什么或做错了什么?
5个回答

5
尝试更改:
List<IProduct> productList = new List<RivWorks.Model.Objects.Product>();

致:

List<IProduct> productList = new List<IProduct>();

或者(如果你需要在返回列表之前使用列表的元素作为它们的具体实现而不是接口):
List<RivWorks.Model.Objects.Product> productList = 
    new List<RivWorks.Model.Objects.Product>();

// Do some work here.

return productList.Cast<IProduct>().ToList();

1
虽然这样做是可行的,但似乎将其转换为List<IProduct>是不必要的工作,你可以直接从List<IProduct>开始。 - Brett Allen
@Aequitarum - 这取决于他是否想要使用RivWorks.Model.Objects.Product列表中的项目而不是与接口一起使用。为简单起见,他已经删除了部分代码...他可能需要针对Product特定的方法。 - Justin Niessner
是的,我正在对 IProduct 属性做大量工作 - 根据数据库中可用的内容,我可以从几个不同的来源填充它。 - Keith Barrows

4
你正在创建一个Product列表,但它需要一个IProduct列表。在这种情况下,这两个是不可互换的(如果有人试图将不是ProductIProduct添加到列表中会怎样?)。请注意更改。
List<IProduct> productList = new List<RivWorks.Model.Objects.Product>();

to

List<IProduct> productList = new List<IProduct>();

4

您需要更改这一行:

List<IProduct> productList = new List<RivWorks.Model.Objects.Product>(); 

to

List<IProduct> productList = new List<IProduct>(); 

由于您返回的是具有接口作为泛型类型的列表,请使用泛型类型实例化列表。

您将能够添加实现它的类。


2
C#中的泛型并不是以这种方式工作的。
请看这里 如果B是A的子类,那么C < B > 不是C < A > 的子类。

1

你假设 Generic List 类理解如果你声明了一个 IProduct 的列表,它就是一个 Product 的列表。你需要按照以下方式声明列表:

List<IProduct> = new List<Iproduct>();

然后您可以添加产品实例。

这是仅在 .NET Framework 版本 4 引入泛型类型的协变性和逆变性的某些情况下才能完成的操作。


2
具体而言,这将在C# 4中适用于泛型已知对于变异是安全的和参数化为引用类型接口委托。List<T>不是一个接口。IList<T>不安全变异。IEnumerable<T>符合要求。 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接