2010-04-14 13 views
66

Ich habe ein Projekt mit allen meinen Schnittstellendefinitionen konvertieren dies hunderte Male vor, aber aus irgendeinem Grund, den ich jetzt diese Störung erhalte:C# Kann nicht implizit Typ Liste <Product> zur Liste <IProduct>

kann nicht implizit Typ ‚System.Collections.Generic.List <RivWorks.DTO.Product>‘ auf ‚System.Collections.Generic konvertieren. Liste < RivWorks.Int erfaces.DataContracts.IProduct > '

Schnittstellendefinition (verkürzt):

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

Betonklassendefinition (verkürzt):

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

In einer anderen Klasse I haben:

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

Irgendwelche Ideen, warum dies könnte passieren? (Und ich bin mir sicher, dass es etwas Einfaches ist!)

Antwort

86

Ja, es ist eine Kovarianzbegrenzung in C#. Sie können eine Liste eines Typs nicht in eine Liste eines anderen Typs konvertieren.

Statt:

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

Sie haben, dies zu tun

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

myList.Add(new dto.Product()); 

Eric Lippert erklärt, warum sie es auf diese Weise umgesetzt: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

(Und warum ist es anders als Arbeits mit Feldern von Elementen).

+0

Sowohl Daniel als auch Kevin antworteten das, obwohl auf unterschiedliche Weise. Bravo! Faire Erklärung der Kontra/Kovarianz. Es ist tatsächlich entweder IN ** oder ** OUT, aber nicht beides. Ich habe .NET 4.0 nicht benutzt, was mir völlig in den Sinn gekommen ist! Danke Leute. –

26

Sie können das nicht tun. Wenn Sie einen List<IProduct> haben, können Sie irgendeinIProduct darin setzen. Wenn Sie also einen Product2 haben, der IProduct implementiert, können Sie ihn in die Liste aufnehmen. Die ursprüngliche Liste wurde jedoch als List<Product> erstellt, sodass jeder, der die Liste verwendet, nur Objekte des Typs Product, nicht Product2, in der Liste erwarten würde.

In .NET 4.0 fügten sie Kovarianz und Kontravarianz für Schnittstellen hinzu, sodass Sie IEnumerable<Product> in IEnumerable<IProduct> konvertieren konnten. Aber das funktioniert immer noch nicht für Listen, da das Listen-Interface es Ihnen erlaubt, "Dinge hineinzulegen" und "Dinge rauszubekommen".

+3

Netter Tipp über die Möglichkeit, IEnumerable –

-3

Versuchen Sie stattdessen:

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

ernst zu nehmen? Weißt du, was das überhaupt bedeutet? – Nix

2

Nun, Sie diese verwenden können!

 class A {} 
     class B : A {} 
     ... 
     List<B> b = new List<B>(); 
     ... 
     List<A> a = new List<A>(b.ToArray()); 

, nun direkte Lösung zu geben,

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

Nur als Hinweis: Covariance and Contravariance in Generics wurde C# 4.0 hinzugefügt.

+1

Wird jedoch nicht in Konstrukten unterstützt, die über IN- und OUT-Kanäle verfügen. Liste ist solch ein Konstrukt, so dass sie keine Kontra/Kovarianz unterstützen! –

+0

Ja, es würde nur funktionieren, wenn IEnumerable verwendet wird – Danvil

1

Dies ist ein kleines Beispiel, wie es geht.

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. "); 
     } 
    } 
Verwandte Themen