List <Product> 형식을 List <IProduct>로 암시 적으로 변환 할 수 없습니다.


89

모든 인터페이스 정의
가있는 프로젝트가 있습니다 : 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>();
    ...

왜 이런 일이 일어날 지 아이디어가 있습니까? (그리고 나는 그것이 사소한 일이라고 확신합니다!)

답변:


114

네, 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

(그리고 항목 배열 작업과 다른 이유).


Daniel과 Kevin은 서로 다른 방식으로 대답했습니다. 브라보! 반대 / 공분산에 대한 공정한 설명. 실제로 IN 또는 OUT이지만 둘다는 아닙니다. 내 마음을 완전히 미끄러 뜨린 .NET 4.0을 사용하지 않았습니다! 감사합니다.
Keith Barrows

39

당신은 그렇게 할 수 없습니다. 가있는 경우 아무거나List<IProduct> 넣을 수 있습니다 . 따라서 구현 하는 것이 있으면 목록에 넣을 수 있습니다. 그러나 원래의 목록은 다음과 같이 생성 된 경우에만 기대 목록을 사용하는 모든 유형의 객체 있도록, 하지, 목록에 표시 할 수 있습니다. IProductProduct2IProductList<Product>ProductProduct2

당신은 변환 할 수 있도록 .NET 4.0, 그들은 인터페이스에 대한 공분산 및 contravariance 추가 IEnumerable<Product>IEnumerable<IProduct>. 그러나 이것은 여전히 ​​목록에 대해서는 작동하지 않습니다. 목록 인터페이스를 통해 "물건을 넣거나" "물건을 꺼낼"수 있기 때문입니다.


8
IEnumerable을 사용 할 수있는 대한 좋은 팁
리 Englestone

나는 여전히이 부분에 약간 혼란스러워한다 :> 그래서 목록을 사용하는 모든 사람은 목록에 Product2가 아닌 Product 유형의 개체 만있을 것으로 예상 할 것입니다. 사용자는 왜 그런 가정을했을까요? List <IProduct>로 선언 된 것을 사용하는 경우 자동으로 요소를 한 구현 또는 다른 구현으로 다운 캐스트 할 수있을 것으로 기대하지 않습니다. (MSFT가 좋아하지 않는 기발한 선택 일 수도 있지만, 그렇지 않다면 그들의 추론을 이해하고 싶습니다.)
Eleanor Holley


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());
}

2

이것은 그것을 수행하는 방법에 대한 작은 예입니다.

    public void CreateTallPeople()
    {
        var tallPeopleList = new List<IPerson>
        {
            new TallPerson {Height = 210, Name = "Stevo"},
            new TallPerson {Height = 211, Name = "Johno"},
        };
        InteratePeople(tallPeopleList);
    }

    public void InteratePeople(List<IPerson> people)
    {
        foreach (var person in people)
        {
            Console.WriteLine($"{person.Name} is {person.Height}cm tall.  ");
        }
    }

-3

대신 이것을 시도하십시오.

List<contracts.IProduct> myList = new List<contracts.IProduct>((new List<dto.Product>()).Cast<contracts.IProduct>());

7
진지하게? 그게 무슨 뜻인지 알아?
Nix
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.