IList ne zaman ve List ne zaman kullanılır?


180

IList'in arayüz olduğunu ve List'in somut tip olduğunu biliyorum ama her birini ne zaman kullanacağımı hala bilmiyorum. Şu anda yaptığım şey, Arabirimi kullandığım Sort veya FindAll yöntemlerine ihtiyaç duymam. Haklı mıyım? Arayüzü veya beton tipini ne zaman kullanacağınıza karar vermenin daha iyi bir yolu var mı?


1
Birisi hala merak ediyorsa, en iyi cevapları burada buluyorum: stackoverflow.com/questions/400135/listt-or-ilistt
Crismogram

Yanıtlar:


175

Takip ettiğim iki kural var:

  • Çalışacak en temel türü kabul edin
  • Kullanıcınızın ihtiyaç duyacağı en zengin türü döndürün

Bu nedenle, bir koleksiyon alan bir işlev veya yöntem yazarken, bir Liste değil, bir IList <T>, bir ICollection <T> veya IEnumerable <T> almak için yazın. Genel arabirimler heterojen listelerde bile çalışmaya devam edecektir çünkü System.Object de T olabilir. Bunu yapmak, bir Yığın veya başka bir veri yapısı kullanmaya devam ederseniz baş ağrısından tasarruf etmenizi sağlar. Eğer fonksiyonda yapmanız gereken tek şey bunun üzerinden her şeyse, IEnumerable <T> gerçekten sormanız gereken tek şeydir.

Öte yandan, bir nesneyi bir işlevin dışına döndürürken, kullanıcıya, dolaşmak zorunda kalmadan mümkün olan en zengin işlem kümesini vermek istersiniz. Bu durumda, dahili olarak bir Liste <T> ise, bir kopyayı Liste <T> olarak döndürün.


43
Giriş / çıkış türlerine farklı davranmamalısınız. Giriş ve çıkış türlerinin her ikisi de, müşterilerin ihtiyaçlarını destekleyecek en temel tür (tercihen arabirim) olmalıdır. Kapsülleme, müşterilere sınıfınızın mümkün olduğunca az uygulanması hakkında bilgi vermeye dayanır. Somut bir Liste döndürürseniz, tüm müşterilerinizi yeniden derlemeye / güncellemeye zorlamadan daha iyi bir türe geçemezsiniz.
Kül

11
Ben 2 kural ile aynı fikirde değilim ... Ben bu durumda IList (daha iyi IEnumarable) dönerken en ilkel türü ve özellikle kullanmak istiyorum ve içinde fonksiyonunuzda List ile çalışmalısınız. Sonra "add" ya da "sort" 'e ihtiyacınız olduğunda daha sonra ihtiyacınız varsa Collection kullanın ve sonra List kullanın. Benim zor kuralım şöyle olurdu: Her zaman IENumarable ile BAŞLATIN ve daha fazlasına ihtiyacınız varsa uzatın ...
ethem

2
Size kolaylık sağlamak için, "iki kural" ın bir adı vardır: sağlamlık ilkesi (diğer adıyla Postel yasası) .
easoncxz

Tartışmanın hangi tarafı en basit veya en zengin tipin geri döndürüleceği konusunda ne olursa olsun, göz önünde bulundurulması gereken bir şey, çok basitleştirilmiş bir arayüz döndürürken, tüketen kod çoğu zaman - her zaman olmasa da - anlamak if...elseiçin isanahtar kelimeyle bir zincir kullanabilir bunun için çok daha zengin bir tür ve sonuçta döküm ve yine de kullanarak. Yani değiliz mutlaka yerine sadece engellemeyecek, temel bir arayüze kullanarak gizlemek şey garanti. Ancak bunu zorlaştırmak, tüketen kodun yazarını nasıl kullandıklarını iki kez düşünmesini sağlayabilir.
Panzercrisis

6
Özellikle bu bir hizmet / api sınırında ise, Nokta # 2 hakkında kesinlikle katılmıyorum. Değiştirilebilir koleksiyonlarını dönersek koleksiyonları "canlı" ve benzeri yöntemler çağıran olduğu izlenimini verebilir Add()ve Remove()sadece koleksiyon ötesinde etkileri olabilir. Gibi bir salt okunur arabirimi döndürmek IEnumerable, genellikle veri alma yöntemleri için gitmek için bir yoldur. Tüketiciniz bunu daha zengin bir türe gerektiği gibi yansıtabilir.
STW

56

FxCop tarafından kontrol edilen Microsoft yönergeleri, genel API'larda Liste <T> kullanımını engellemez - IList <T> 'i tercih edin.

Bu arada, hemen hemen her zaman tek boyutlu dizileri IList <T> olarak ilan ediyorum, bu da sürekli olarak Array.Length yerine IList <T> .Count özelliğini kullanabileceğim anlamına geliyor. Örneğin:

public interface IMyApi
{
    IList<int> GetReadOnlyValues();
}

public class MyApiImplementation : IMyApi
{
    public IList<int> GetReadOnlyValues()
    {
        List<int> myList = new List<int>();
        ... populate list
        return myList.AsReadOnly();
    }
}
public class MyMockApiImplementationForUnitTests : IMyApi
{
    public IList<int> GetReadOnlyValues()
    {
        IList<int> testValues = new int[] { 1, 2, 3 };
        return testValues;
    }
}

3
Bu açıklamayı seviyorum / örnek en çok!
JonH

28

İnsanların her zaman göz ardı ettiği önemli bir şey var:

IList<T>Parametreyi kabul eden bir şeye düz bir dizi geçirebilir ve ardından IList.Add()bir çalışma zamanı istisnası arayabilir ve alabilirsiniz:

Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.

Örneğin, aşağıdaki kodu göz önünde bulundurun:

private void test(IList<int> list)
{
    list.Add(1);
}

Bunu aşağıdaki gibi çağırırsanız, bir çalışma zamanı istisnası alırsınız:

int[] array = new int[0];
test(array);

Bunun nedeni, düz dizilerin IList<T> Liskov ikame ilkesini ihlal etmesidir.

Bu nedenle, eğer arıyorsanız, yerine IList<T>.Add()bir List<T>yerine ihtiyaç duyabilirsiniz IList<T>.


Bu her arayüz için önemsiz bir şekilde doğrudur. Argümanınızı takip etmek istiyorsanız, hiçbir zaman hiçbir arayüz kullanmamayı iddia edemezsiniz, çünkü bazı uygulamaları atlayabilir. Eğer, diğer taraftan, tercih OP tarafından verilen öneri düşünün List<T>üzerinde IList<T>, ayrıca nedenlerinden bilmelidir IList<T>tavsiye edilir. (Örneğin blogs.msdn.microsoft.com/kcwalina/2005/09/26/… )
Micha Wiedenmann

3
@MichaWiedenmann Buraya verdiğim cevap ne zaman aradığınıza özgü IList<T>.Add(). Sana demiyorum olmamalı kullanmak IList<T>- Sadece olası bir hatadır işaret ediyorum. (Ben kullanma eğiliminde IEnumerable<T>veya IReadOnlyList<T>veya IReadOnlyCollection<T>tercih için IList<T>eğer yapabilirsem.)
Matthew Watson

24

Parametreleri almak için Lee'nin tavsiyelerine katılıyorum, ama geri dönmüyorum.

Bir arabirim döndürmek için yöntemlerinizi belirtirseniz, daha sonra tüketen yöntemi bilmeden kesin uygulamayı değiştirmekte özgür olduğunuz anlamına gelir. Asla bir List <T> değiştirmek zorunda olacağını düşündüm ama daha sonra sağladığı ekstra işlevsellik için özel bir liste kitaplığı kullanmak için değiştirmek zorunda kaldı. Ben sadece bir IList döndü çünkü <T> kütüphaneyi kullanan insanların hiçbiri kodlarını değiştirmek zorunda değildi.

Tabii ki bu sadece harici olarak görünen yöntemlere (yani genel yöntemler) uygulanmalıdır. Kişisel olarak iç kodda bile arayüzler kullanıyorum, ancak kırma değişiklikleri yaparsanız tüm kodu kendiniz değiştirebildiğiniz için kesinlikle gerekli değildir.


22

IEnumerable
Amacınıza uygun en az spesifik türü denemeli ve kullanmalısınız.
IEnumerabledaha az spesifiktir IList. Bir koleksiyondaki öğeler arasında geçiş yapmak istediğinizde
kullanılır IEnumerable.

IList
IList uygular IEnumerable. Koleksiyonunuza dizine göre erişmeniz gerektiğinde, öğeler ekleyip sildiğinizde vb.
Kullanmalısınız IList.

Listeyi
List uygular IList.


3
Yararlı olarak işaretlenmiş mükemmel, net cevap. Ancak, çoğu geliştirici için, çoğu zaman, program boyutu ve performansındaki küçük farkın endişelenmeye değmeyeceğini ekliyorum: şüpheniz varsa, sadece bir Liste kullanın.
Graham Laight

9

Mümkün olan en düşük taban türünü kullanmak her zaman en iyisidir. Bu, arayüzünüzün uygulayıcısına veya yönteminizin tüketicisine, perde arkasında istediklerini kullanma fırsatı verir.

Koleksiyonlar için mümkün olduğunda IEnumerable'ı kullanmayı hedeflemelisiniz. Bu, en fazla esnekliği sağlar, ancak her zaman uygun değildir.


1
Mümkün olan en düşük baz tipini kabul etmek her zaman en iyisidir . Geri dönmek farklı bir hikaye. Hangi seçeneklerin yararlı olacağını seçin. Yani müşterinizin dizine alınmış erişimi kullanmak isteyebileceğini mi düşünüyorsunuz? Onları tutun ToList()senin döndü -ing IEnumerable<T>bir liste zaten olduğunu ve bir dönüş IList<T>yerine. Artık müşteriler, çaba harcamadan sağlayabileceğiniz şeylerden faydalanabilirler.
Timo

5

Tek bir yöntemde (hatta bazı durumlarda tek bir sınıfta veya derlemede) çalışıyorsanız ve dışarıdaki hiç kimse ne yaptığınızı görmezse, bir Listenin doluluğunu kullanın. Ancak, dış kodla etkileşime giriyorsanız, örneğin bir yöntemi bir listeden döndürürken olduğu gibi, yalnızca kendinizi belirli bir uygulamaya bağlamadan, özellikle de sizin sonra kodu. Somut bir türle başladıysanız ve aynı arayüzü kullanıyor olsa bile başka bir tanesiyle değiştirmeye karar verdiyseniz, bir arayüz veya soyut taban türüyle başlamadığınız sürece başka birinin kodunu kıracaksınız.


4

Bu tür şeyler için zor ve hızlı kurallar olduğunu düşünmüyorum, ancak genellikle kesinlikle gerekli olana kadar mümkün olan en hafif yolu kullanma kılavuzuna giriyorum.

Diyelim ki bir Personsınıfınız ve bir Groupsınıfınız var. Bir Groupörneğin çok sayıda insanı var, bu yüzden burada bir Liste mantıklı olurdu. Liste nesnesini bildirdiğimde Groupbir IList<Person>ve kullanacağım List.

public class Group {
  private IList<Person> people;

  public Group() {
    this.people = new List<Person>();
  }
}

Ve eğer her şeye bile ihtiyacınız IListyoksa, her zaman da kullanabilirsiniz IEnumerable. Modern derleyiciler ve işlemcilerle, gerçekten herhangi bir hız farkı olduğunu düşünmüyorum, bu yüzden bu sadece bir stil meselesi.


3
neden ilk etapta bir liste yapmıyorsunuz? Hala bir IList yapmaktan neden bonus aldığınızı anlamıyorum, sonra yapıcıda bir Liste haline getirin <>
chobo2

Açıkça bir List <T> nesnesi oluşturuyorsanız, arabirimin avantajını kaybedersiniz?
The_Butcher

4

Çoğu zaman en genel kullanılabilir türü, bu durumda IList'i veya daha iyi IEnumerable arayüzünü kullanmaktan daha iyi olursunuz, böylece uygulamayı daha sonra kolayca değiştirebilirsiniz.

Ancak, .NET 2.0, can sıkıcı bir şey var - IList bir Sort () yöntemi yoktur. Bunun yerine ürünle birlikte verilen adaptörü kullanabilirsiniz:

ArrayList.Adapter(list).Sort()

2

Arabirimi yalnızca gereksinim duyduğunuzda kullanmalısınız, örneğin listeniz Liste dışında bir IList uygulamasına yayınlanmışsa. Örneğin veri alırken IListleri bir NHibernate torba nesnesine çeviren NHibernate kullandığınızda bu doğrudur.

Liste, belirli bir koleksiyon için kullanacağınız tek uygulamasa, bunu somut bir Liste uygulaması olarak bildirmekten çekinmeyin.


1

Genellikle karşılaştığım durumlarda nadiren IList kullanıyorum.

Genellikle sadece bir yönteme argüman olarak kullanırım

void ProcessArrayData(IList almostAnyTypeOfArray)
{
    // Do some stuff with the IList array
}

Bu, bazen gerçekleşen IList'i değil, IEnumerable'ı kullanmadığı sürece .NET çerçevesindeki hemen hemen tüm dizilerde genel işlem yapmamı sağlayacaktır.

Gerçekten ihtiyacınız olan işlevsellik türüne iner. Çoğu durumda List sınıfını kullanmanızı öneririm. IList, bir koleksiyon içinde kapsüllemek istediğiniz bazı çok özel kurallara sahip olabilecek özel bir dizi oluşturmanız gerektiğinde en iyisidir, böylece kendinizi tekrarlamamanız, ancak .NET'in bunu bir liste olarak tanımasını istemeniz gerekir.


1

AList nesnesi, bir liste oluşturmanıza, bir şeyler eklemenize, listeyi kaldırmanıza, güncellemenize, dizine eklemenize vb. Olanak sağlar. Liste, yalnızca nesne türünü belirttiğiniz genel bir Listeyi istediğinizde kullanılır ve işte budur.

IList ise bir arayüzdür. Temel olarak, kendi Liste türünüzü oluşturmak istiyorsanız, BookList adlı bir liste sınıfı söyleyin, o zaman yeni sınıfınıza temel yöntemleri ve yapıyı vermek için Arabirimi kullanabilirsiniz. IList, List'i uygulayan kendi özel alt sınıfınızı oluşturmak istediğiniz zaman içindir.

Başka bir fark: IList bir Arayüzdür ve somutlaştırılamaz. Liste bir sınıftır ve somutlaştırılabilir. Anlamı:

IList<string> MyList = new IList<string>();

List<string> MyList = new List<string>
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.