我有一个包含所有界面定义的项目:RivWorks.Interfaces
我有一个项目,我定义具体的实施:RivWorks.DTO
之前我已经完成了数百次,但出于某种原因我现在收到了这个错误:
无法隐式转换类型'System.Collections.Generic.List< RivWorks.DTO.Product>'到'System.Collections.Generic.List< RivWorks.Interfaces.DataContracts.IProduct>'
接口定义(缩写):
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; }
...
}
}
具体类定义(缩写):
namespace RivWorks.DTO
{
[DataContract(Name = "Product", Namespace = "http://rivworks.com/DataContracts/2009/01/15")]
public class Product : IProduct
{
#region Constructors
public Product() { }
public Product(Guid ProductID)
{
Initialize(ProductID);
}
public Product(string SKU, Guid CompanyID)
{
using (RivEntities _dbRiv = new RivWorksStore(stores.RivConnString).NegotiationEntities())
{
model.Product rivProduct = _dbRiv.Product.Where(a => a.SKU == SKU && a.Company.CompanyId == CompanyID).FirstOrDefault();
if (rivProduct != null)
Initialize(rivProduct.ProductId);
}
}
#endregion
#region Private Methods
private void Initialize(Guid ProductID)
{
using (RivEntities _dbRiv = new RivWorksStore(stores.RivConnString).NegotiationEntities())
{
var localProduct = _dbRiv.Product.Include("Company").Where(a => a.ProductId == ProductID).FirstOrDefault();
if (localProduct != null)
{
var companyDetails = _dbRiv.vwCompanyDetails.Where(a => a.CompanyId == localProduct.Company.CompanyId).FirstOrDefault();
if (companyDetails != null)
{
if (localProduct.alternateProductID != null && localProduct.alternateProductID > 0)
{
using (FeedsEntities _dbFeed = new FeedStoreReadOnly(stores.FeedConnString).ReadOnlyEntities())
{
var feedProduct = _dbFeed.AutoWithImage.Where(a => a.ClientID == companyDetails.ClientID && a.AutoID == localProduct.alternateProductID).FirstOrDefault();
if (companyDetails.useZeroGspPath.Value || feedProduct.GuaranteedSalePrice > 0) // kab: 2010.04.07 - new rules...
PopulateProduct(feedProduct, localProduct, companyDetails);
}
}
else
{
if (companyDetails.useZeroGspPath.Value || localProduct.LowestPrice > 0) // kab: 2010.04.07 - new rules...
PopulateProduct(localProduct, companyDetails);
}
}
}
}
}
private void PopulateProduct(RivWorks.Model.Entities.Product product, RivWorks.Model.Entities.vwCompanyDetails RivCompany)
{
this.ProductID = product.ProductId;
if (product.alternateProductID != null)
this.alternateProductID = product.alternateProductID.Value;
this.BackgroundColor = product.BackgroundColor;
...
}
private void PopulateProduct(RivWorks.Model.Entities.AutoWithImage feedProduct, RivWorks.Model.Entities.Product rivProduct, RivWorks.Model.Entities.vwCompanyDetails RivCompany)
{
this.alternateProductID = feedProduct.AutoID;
this.BackgroundColor = Helpers.Product.GetCorrectValue(RivCompany.defaultBackgroundColor, rivProduct.BackgroundColor);
...
}
#endregion
#region IProduct Members
public Guid ProductID { get; set; }
public long alternateProductID { get; set; }
public Guid CompanyId { get; set; }
...
#endregion
}
}
在另一堂课中我有:
using dto = RivWorks.DTO;
using contracts = RivWorks.Interfaces.DataContracts;
...
public static List<contracts.IProduct> Get(Guid companyID)
{
List<contracts.IProduct> myList = new List<dto.Product>();
...
为什么会发生这种情况的任何想法? (我相信这很简单!)
答案 0 :(得分:98)
是的,它是C#中的协方差限制。您无法将一种类型的列表转换为另一种类型的列表。
而不是:
List<contracts.IProduct> myList = new List<dto.Product>();
你必须这样做
List<contracts.IProduct> myList = new List<contracts.IProduct>();
myList.Add(new dto.Product());
Eric Lippert解释了为什么他们这样实现它: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
(为什么它与使用项目数组不同)。
答案 1 :(得分:35)
你做不到。如果您有List<IProduct>
,则可以在其中添加任何 IProduct
。因此,如果您有Product2
实现IProduct
,则可以将其放入列表中。但原始列表创建为List<Product>
,因此使用该列表的任何人都只希望列表中包含Product
类型而非Product2
的对象。
在.NET 4.0中,他们为界面添加了协方差和逆变,因此您可以将IEnumerable<Product>
转换为IEnumerable<IProduct>
。但这仍然不适用于列表,因为列表界面允许你“把东西放进去”和“把东西拿出来”。
答案 2 :(得分:5)
正如一句话:C {4.0中添加了Covariance and Contravariance in Generics。
答案 3 :(得分:4)
好吧,你可以用它!
class A {}
class B : A {}
...
List<B> b = new List<B>();
...
List<A> a = new List<A>(b.ToArray());
现在,直接解决,
using dto = RivWorks.DTO;
using contracts = RivWorks.Interfaces.DataContracts;
...
public static List<contracts.IProduct> Get(Guid companyID) {
List<dto.Product> prodList = new List<dto.Product>();
...
return new List<contracts.IProduct>(prodList.ToArray());
}
答案 4 :(得分:2)
这是一个如何做的小例子。
(newtype) new = (newtype) in;
String Url = new.appropriatemethod();
答案 5 :(得分:-3)
请改为尝试:
List<contracts.IProduct> myList = new List<contracts.IProduct>((new List<dto.Product>()).Cast<contracts.IProduct>());