C # - स्पष्ट रूप से सूची <Product> को List <IProduct> में नहीं बदल सकते


89

मेरे पास मेरी सभी इंटरफ़ेस परिभाषाओं के साथ एक परियोजना है: रिववॉर्क्स।इंटरफ़ोर्स
मेरे पास एक ऐसी परियोजना है जहां मैं ठोस निहितार्थों को परिभाषित करता हूं: रिववॉर्क्स। डीटीओ

मैंने पहले भी ऐसा सैकड़ों बार किया है लेकिन किसी कारण से मुझे अब यह त्रुटि मिल रही है:

संक्षेप में 'System.Collections.Generic.List <RivWorks.DTO.Product>' को 'System.Collections.Generic.List <RivWorks.Interfaces.Datafontonts.s.product>' में नहीं बदल सकता

इंटरफ़ेस परिभाषा (छोटा):

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

एरिक लिपर्ट बताते हैं कि उन्होंने इसे इस तरह क्यों लागू किया: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

(और यह वस्तुओं के सरणियों के साथ काम करने से अलग क्यों है)।


डैनियल और केविन दोनों ने इसका जवाब दिया, हालांकि अलग-अलग तरीकों से। वाहवाही! श्वसन / सहवास का उचित विवरण। यह वास्तव में IN या OUT है, लेकिन दोनों में नहीं। .NET 4.0 का उपयोग नहीं करने से मेरा दिमाग पूरी तरह से फिसल गया! धन्यवाद दोस्तों।
कीथ बैरो

39

आप ऐसा नहीं कर सकते। यदि आपके पास एक है List<IProduct>, तो आप इसमें कोई भी डाल सकते हैं IProduct। इसलिए यदि आपके पास कोई ऐसा उपकरण है Product2जिसे IProductआप सूची में डाल सकते हैं। लेकिन मूल सूची के रूप में बनाया गया था List<Product>, इसलिए सूची का उपयोग करने वाला कोई भी व्यक्ति केवल प्रकार की वस्तुओं की अपेक्षा करेगा Product, Product2सूची में नहीं।

.NET 4.0 में, वे इंटरफेस के लिए सहप्रसरण और contravariance जोड़ा है, तो आप परिवर्तित कर सकते हैं IEnumerable<Product>करने के लिए IEnumerable<IProduct>। लेकिन यह अभी भी सूचियों के लिए काम नहीं करता है, क्योंकि सूची इंटरफ़ेस आपको "सामान रखने" और "सामान बाहर निकालने" दोनों की अनुमति देता है।


8
अच्छा टिप के बारे में IEnumerable का उपयोग करने में सक्षम होने के बारे में
ली Englestone

मैं अभी भी इस हिस्से से थोड़ा भ्रमित हूं:> इसलिए सूची का उपयोग करने वाला कोई भी व्यक्ति केवल उत्पाद की वस्तुओं की अपेक्षा करेगा, उत्पाद 2 सूची में नहीं होगा। उपयोगकर्ता यह धारणा क्यों बनाएगा? अगर मैं सूची के रूप में घोषित कुछ का उपयोग कर रहा हूं <IProduct>, तो मैं उम्मीद नहीं कर सकता कि स्वचालित रूप से तत्वों को एक कार्यान्वयन या किसी अन्य के लिए डाउनकास्ट करने में सक्षम हो। (यह संभव है कि यह सिर्फ एक quirky पसंद है जो मुझे MSFT द्वारा पसंद नहीं है, लेकिन अगर मैं वास्तव में उनके तर्क को समझने की कोशिश नहीं करना चाहता हूं।)
एलेनोर होली

5

बस एक टिप्पणी के रूप में: जेनरिक में कोवरियन और कंट्रावेरियन को सी # 4.0 में जोड़ा गया था।


1
लेकिन उन निर्माणों में समर्थित नहीं है जिनमें IN और OUT दोनों चैनल हैं। सूची <टी> एक ऐसा निर्माण है ताकि वे गर्भनिरोधक / सहसंयोजक का समर्थन न करें!
कीथ बैरो

हां, यह केवल तभी काम करेगा जब एक IEnumerable <contracts.IProduct> का उपयोग करके
Danvil

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
गंभीरता से? क्या आप जानते हैं कि इसका मतलब क्या है?
निस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.