<T> Listesini <Arayüz> Listesine Yayınla


110
public interface IDic
{
    int Id { get; set; }
    string Name { get; set; }
}
public class Client : IDic
{

}

Nasıl yayın yapabiliyorsa List<Client>için List<IDic>?

Yanıtlar:


250

Onu çeviremezsiniz (referans kimliğini koruyarak) - bu güvenli olmaz. Örneğin:

public interface IFruit {}

public class Apple : IFruit {}
public class Banana : IFruit {}

...

List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());

// Eek - it's a banana!
Apple apple = apples[0];

Artık bir dönüştürebilirsiniz List<Apple>bir etmek IEnumerable<IFruit>sebebiyle kovaryanslarına .NET 4 / C # 4'te, ancak isterseniz bir List<IFruit>bir oluşturmak zorundayız yeni liste. Örneğin:

// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();

// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();

Ancak bu, orijinal listeyi yayınlamakla aynı şey değildir - çünkü artık iki ayrı liste var. Bu güvenlidir, ancak tek bir liste üzerinde yapılan değişiklikler olduğunu anlamamız gerekir olmayacak diğer listede görülebilir. ( Listelerin atıfta bulunduğu nesnelerde yapılan değişiklikler elbette görülecektir.)


6
sanki 'hala binadalar' gibi!
Andras Zoltan

1
Kovaryans listesi yapmak ile yeni Liste yapmak <IFruit> () arasındaki fark nedir; sonra orijinal listenin üzerinde bir foreach ve her bir öğeyi IFruit listesine ekleyerek? Her şekilde ... nesne referansı aynı olacaktır, değil mi? Öyleyse ... eğer bu doğruysa, kişisel olarak tüm listeyi doğrudan yayınlayamayacağınız benim için pek mantıklı değil. ?
Robert Noack

3
@RobertNoack: "Nesne referansı" ile neyi kastediyorsunuz? Her bir öğenin nesne referansı aynıdır, ancak bu, liste referansının kendisini yayınlamakla aynı değildir. Varsayalım ki referansı atabileceğinizi varsayalım, böylece List<IFruit>aslında bir List<Apple>. Buna bir Bananareferans eklerseniz ne olmasını beklersiniz List<IFruit>?
Jon Skeet

1
Ah. Sanırım okumayı öğrenmem gerekiyor. Orijinal cevabın listedeki nesnelerin derinlemesine kopyalanıp yeniden yaratılacağını söylediğini düşündüm ki bu bana mantıklı gelmedi. Ancak aynı nesnelerle yalnızca yeni bir listenin oluşturulduğu kısmı açıkça kaçırdım.
Robert Noack

2
@ TrươngQuốcKhánh: Hiçbir fikrim yok nasıl herhangi gibi kod görünüyor, yoksa olup olmadığı usingiçin yönergesini System.Linq, ya da neden ben emin misin yardım edebilmek için beklemek ne kadar değilim, bunu aramaya çalışıyoruz. Daha fazla araştırma yapmanızı öneririm ve hala takılıp kalırsanız, tekrarlanabilir minimum bir örnekle soru sorarsınız .
Jon Skeet

6

Bir Cast yineleyici ve .ToList ():

List<IDic> casted = input.Cast<IDic>().ToList() hile yapacak.

Başlangıçta kovaryansın işe yarayacağını söyledim - ama Jon'un haklı olarak işaret ettiği gibi; hayır olmayacak!

Ve başlangıçta aptalca ToList()görüşmeyi de bıraktım


Castdöner bir IEnumerable<T>değil, bir List<T>- ve hayır, kovaryans olmaz o güvensiz olacağından, bu dönüşümü sağlayacak - cevabım bakın.
Jon Skeet

Bağlandığınız sayfadan: "Yalnızca arabirim türleri ve temsilci türlerinin değişken türü parametreleri olabilir"
Jon Skeet

@Jon - Yorumunuzu ToList()okumadan önce eksik olduğunu fark ettim ; ama evet, sizin de gösterdiğiniz gibi, kovaryans işe yaramayacak! Doh!
Andras Zoltan

Sağ. CastTür bağımsız değişkenini belirttiğiniz sürece .NET 4'te çağrıya ihtiyacınız olmadığı anlamına geldiğinden kovaryans yine de yardımcı olabilir ToList.
Jon Skeet

5

Ben de bu problemi yaşadım ve Jon Skeet'in cevabını okuduktan sonra kodumu kullanmaktan List<T>değiştirdim IEnumerable<T>. Bunun OP'ın orijinal soruya cevap olmamasına rağmen yayınlayabileceğim Nasıl List<Client>içinList<IDic> böylece bunu yapmak için gereksinimini ortadan yok ve bu sorunla karşılaştıktan başkalarına yararlı olabilir. Elbette bu, kullanımını gerektiren kodun List<IDic>sizin kontrolünüz altında olduğunu varsayar .

Örneğin:

public void ProcessIDic(IEnumerable<IDic> sequence)
{
   // Implementation
}

Onun yerine:

public void ProcessIDic(List<IDic> list)
{
   // Implementation
}

3

LINQ kullanabiliyorsanız, bunu yapabilirsiniz ...

List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();

3
List<Client> listOfA = new List<Client>();
List<IDic> list = listOfA.Cast<IDic>().ToList();

0

Sadece yeni oluşturmak List<IDic>ve tüm unsurları aktarmakla mümkündür .


Genel anlamı diğer tüm cevaplarla aynı olduğuna göre neden olumsuz oy verildiğine dair herhangi bir yorum var mı?
Piotr Auguscik

Tahminime göre, sadece yeni bir liste oluşturmanın mümkün olduğunu söylediğiniz için, ancak diğerleri tam tersini yayınladı ... benim olumsuz oyum değil)
musefan

Yeni listeler oluşturuyorlar ama yeni operatörlerle değil, bu yaptıkları gerçeğini değiştirmiyor.
Piotr Auguscik

0

.Net 3.5'te aşağıdakileri yapabilirsiniz:

List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());

Bu durumda List için yapıcı bir IEnumerable alır.
list olsa da yalnızca IEnumerable'a dönüştürülebilir. Olsa myObj ISomeInterface dönüştürülebilir olabilir tip IEnumerable IEnumerable dönüştürülebilir değildir.


Sorun bu listenin bir kopyasını, orijinal listedeki işlemleri yapmak istiyorum çoğu zaman yapar
rulo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.