2017-07-27 58 views
41

Listeye List den dönüştürülemez: Ben böyle kurdunuz <Foo>

abstract class Foo {} 
class Bar : Foo {} 

ve başka yerlerde bu formun bir yöntem:

void AddEntries(List<Foo>) {} 

Ben kullanarak bu yöntemi çağırmak çalışıyorum türü nesne listesi Bar

List<Bar> barList = new List<Bar>() 
AddEntries(barList); 

ama bu bana verir Hata:

cannot convert from List<Bar> to List<Foo>

Bu sorunun çevresinde zaten var mı? Soyut sınıfını kullanarak yöntem tanımını tutmalıyım.

+1

mu C#:

sorunu çözmek için, generics kullanabilir? Foo> 'gibi Java'yı genişletir? – dbush

+2

@dbush Evet, C# 'nin sürümü kabul edilen yanıtta – Harrichael

+4

@harrichael Java'dan farklı olarak, C# genel kovaryansı destekliyor, bu yüzden daha iyi bir seçenek var (Rob'un cevabı bakın) –

cevap

64

listenize AddEntries jenerik yapmak ve bu

void AddEntries<T>(List<T> test) where T : Foo 
{ 
    //your logic 
} 

olarak değiştirin fazla bilgi için Constraints on Type Parameters göz at olabilir.

60

Bu şekilde Covariance and Contravariance in Generics from docs.microsoft.com okunduğundan, özellikle "Covariant Type Parametreli Genel Arabirimler" bölümü, üzerinde çalıştığınız senaryoyu kapatacaktır. Size AddEntries yöntemin imzasını değiştirmek (edebilirsiniz) Kısacası

:

static void AddEntries(IEnumerable<Foo> entries) 

(IEnumerable<Foo> yerine List<Foo> ait kullanımına dikkat) Eğer aradığınızı yapmak mümkün olacak yapmak. Burada

belirli bir fark IEnumerable<T> ve List<T> farklı beyan olmasıdır:

public interface IEnumerable<out T> : IEnumerable 
public class List<T> : IList<T>, ... ... 

bu demektir ki bildirdiğinden olduğunu gösterir IEnumerable<T> bildiriminde out Önemli olan farkı (docs.microsoft.com'dan alınan tanım ile):

Covariance: Enables you to use a more derived type than originally specified.

+1

Yöntem adının AddEntries olduğunu düşünürsek, OP'nin IEnumerable kullanması olası değildir. – Taemyr

+0

@Taemyr OP, ancak bir 'interface' tanımlayabilir. – wizzwizz4

+7

@Taemyr: "AddEntries" ifadesinin "Bu girişleri başka bir listeye ekle", "Bu listeye bazı girişler ekle" anlamına gelmediğini varsayıyorum. Aksi takdirde ne cevap ne olursa olsun, bir FooChild'i bir 'List ' listesine ekleyemediği için onun için çalışacaktır. –

43

Bu, basit bir nedenden dolayı izin verilmez. Aşağıdaki derler varsayalım:

AddEntries(new List<Bar>()); 

void AddEntries(List<Foo> list) 
{ 
    // list is a `List<Bar>` at run-time 
    list.Add(new SomethingElseDerivingFromFoo()); // what ?! 
} 

kodunuzu derlemek istiyorsanız, size aslında bir List<Bar> (çalışma zamanı tip) SomethingElseDerivingFromFoo eklendi (tüm jenerik listeleri anlamsız kılar) güvenli olmayan bir ek var. `List

void AddEntries<T>(List<T> list) where T:Foo 
{ 

} 
+3

Açıklamak için niçin * neden * çalışmayı yapmak için bir yol göstermek yerine, oyuncuyu yapamazsın. –

+0

Anlamıyorum. Bu [tamamen geçerli bir kod parçasıdır] (http://ideone.com/xoNJX8). Sadece türetilmiş sınıfta sağlanan herhangi bir ek işlevsellik (açıkça casting olmadan) güvenemezsiniz. – Phylogenesis

+1

@Phylogenesis 'AddEntries' Listesinden 'öğesini arayamazsınız, çünkü bu listeye' SomethingElseDerivingFromFoo 'eklediyseniz, garip bir davranış olur (List 'içinde bir' SomethingElseDerivingFromFoo' öğesi vardır. kod Ben mükemmel derlenmiş yayınladım – user3185569

İlgili konular