Dizi neden IList uygular?


141

System.Array sınıfının tanımına bakın

public abstract class Array : IList, ...

Teorik olarak, bu parçayı yazabilmeli ve mutlu olabilmeliyim

int[] list = new int[] {};
IList iList = (IList)list;

Ayrıca iList'ten herhangi bir yöntemi çağırabilmeliyim

 ilist.Add(1); //exception here

Benim sorum neden istisna değil, Array neden IList'i uyguluyor ?


22
Güzel soru. Yağ arayüzleri fikrini hiç sevmedim (bu tür bir tasarım için teknik terim).
Konrad Rudolph


2
Aslında LSP ile ilgilenen var mı? Benim için oldukça akademik görünüyor.
Gabe

13
@Gabe, daha büyük kod tabanlarıyla çalışmanız gerekir. Bir davranışı uygulamak (bir arayüzden devralma) ve daha sonra sevmediğiniz / destekleyemediğiniz şeyleri görmezden gelmek koklamak, gizlemek, döküm yapmak ve son olarak: buggy koduna yol açar.
Marius

3
@Gabe, içerdiği varlıkları değil, değişebilirliği ima eden koleksiyon. Sınıfınızı hem IRWList <> hem de IReadList <> uygulayan bir türün üyesi yapabilir, IRWList <> olarak sınıfınızda dahili olarak kullanabilir ve IReadList olarak gösterebilirsiniz. Evet, karmaşıklığı bir yere koymak zorundasınız, ancak bunun LSP'yi çok iyi bir tasarım prensibi olarak göz ardı etmek için nasıl geçerli olduğunu görmüyorum (ILR'yi tüketiciler açısından daha karmaşık hale getiren olsa da IsReadOnly özelliğini bilmiyordum)
Marius

Yanıtlar:


94

Çünkü bir dizi indekse göre hızlı erişime izin verir ve IList/ IList<T>is bunu destekleyen tek arabirimdir. Yani belki de asıl sorunuz "Neden dizin oluşturucularla sürekli koleksiyonlar için bir arayüz yok?" Ve buna cevabım yok.

Koleksiyonlar için de salt okunur arabirimler yoktur. Ve ben bu indeksler arayüzü ile sabit bir boyut daha bile eksik.

IMO, bir koleksiyonun özelliklerine bağlı olarak birkaç (genel) toplama arabirimi daha olmalıdır. Ve isimleri de farklı olmalı, Listçünkü bir indeksleyici ile bir şey gerçekten aptal IMO.

  • Sadece Numaralandırma IEnumerable<T>
  • Salt okunur ancak dizin oluşturucu yok (.Count, .Contains, ...)
  • Yeniden boyutlandırılabilir, ancak dizinleyici yok, yani (Ekle, Kaldır, ...) akımı gibi ayarla ICollection<T>
  • Dizin oluşturucu ile salt okunur (dizin oluşturucu, dizin oluşturucu, ...)
  • Dizinleyici ile sabit boyut (ayarlayıcılı dizinleyici)
  • Dizinleyici (Ekle, ...) akımıyla değişken boyut IList<T>

Mevcut koleksiyon arayüzlerinin kötü tasarım olduğunu düşünüyorum. Ancak, hangi yöntemlerin geçerli olduğunu söyleyen özelliklere sahip oldukları için (ve bu, bu yöntemlerin sözleşmesinin bir parçasıdır), ikame ilkesini ihlal etmez.


14
Cevap için teşekkürler. Ama soruyu olduğu gibi bırakmayı tercih ederim. Nedeni basit. Arayüz genel bir sözleşmedir. Eğer kişi onu uygularsa, tüm üyeleri tam olarak uygulamalıdır, aksi takdirde LSP'yi kırar ve genellikle kötü kokar, değil mi?
oleksii

16
LSP'yi kırıyor. Listelenmediyse Add (item), beton türünden bağımsız olarak listeye öğe eklemelidir. İstisnai durumlar hariç. Dizi uygulamada, istisnai olmayan bir durumda bir istisna atar, ki bu da kendi içinde kötü bir uygulamadır
Rune FS

2
@smelch Üzgünüm ama LSP yanlış. Bir dizi uygulanmaz addve bu nedenle bu yetenek gerektiğinde yapılacak bir şeyle değiştirilemez.
Rune FS

7
Bunun olduğunu kabul teknik LSP'yi ihlal etmez çünkü sadece dokümantasyon kontrol etmelidir devletler IsFixedSizeve IsReadOnlyözellikleri, kesinlikle ihlal Tell, Do ilkesini not Ask ve en az sürpriz prensibi . Neden 9 yöntemden 4'ü için istisnalar atacağınız zaman bir arabirim uyguluyorsunuz?
Matthew

11
Orijinal sorudan bu yana biraz zaman geçti. Ama şimdi .Net 4.5 ile IReadOnlyList ve IReadOnlyCollection ek arabirimleri var .
Tobias

43

Bölümünü konuşmasında belgelere ilişkin IListdiyor

IList, ICollection arayüzünün torunudur ve jenerik olmayan tüm listelerin temel arayüzüdür. IList uygulamaları üç kategoriye ayrılır: salt okunur, sabit boyutlu ve değişken boyutlu . Salt okunur bir IList değiştirilemez. Sabit boyutlu bir IList, elemanların eklenmesine veya çıkarılmasına izin vermez, ancak mevcut elemanların değiştirilmesine izin verir. Değişken boyutlu bir IList, elemanların eklenmesine, çıkarılmasına ve değiştirilmesine izin verir.

Açıkçası, diziler sabit boyutlu kategoriye girer, bu nedenle arayüzün savunulmasıyla mantıklıdır.


4
Sanırım bir çok arayüzle sonuçlanacaklardı. IListFixedSize, IListReadOnly ...
Magnus

9
aslında dokümantasyon açısından iyi bir cevap. Ama bana göre bir hack gibi görünüyor. Bir sınıfın tüm üyeleri uygulaması için arayüzler ince ve basit olmalıdır.
oleksii

1
@oleksii: Katılıyorum. Arayüzler ve çalışma zamanı istisnaları en zarif kombinasyon değildir. Savunmasında yöntemi açıkça Arrayuygular, Addbu da yanlışlıkla çağrı riskini azaltır.
Brian Rasmussen

Yarattığımız kadar bir uygulamasıdır IListdeğiştirilmesinin hem izin vermez ve ekleme / kaldırma. O zaman belgeler artık doğru değil. : P
Timo

1
@Magnus - .Net 4.5'te IReadOnlyList ve IReadOnlyCollection ek arabirimleri vardır .
RBT

17

Çünkü tüm ILists değişken değil (bakınız IList.IsFixedSizeve IList.IsReadOnly) ve diziler kesinlikle sabit boyutlu listeler gibi davranıyor.

Sorunuz gerçekten "neden jenerik olmayan bir arayüz uyguluyor " ise, cevap jenerikler gelmeden önce bunların etrafta olduğudur.


10
@oleksii: Hayır, LSP'yi kırmaz, çünkü arayüzün IList kendisi değişebilir olmadığını söyler. Aslında değişebilir olması garanti edilirse ve dizi size başka türlü söylerse , o zaman kuralı kıracaktır.
user541686

Aslında, Array jenerik IList<T>olması durumunda IList
Vladimir

5

Bu, salt okunur koleksiyonlarla nasıl başa çıkılacağı ve Array'ın salt okunur olup olmadığı net olmadığı zamanlardan beri var olan bir miras. IList arabiriminde IsFixedSize ve IsReadOnly bayrakları vardır. IsReadOnly bayrağı, koleksiyonun hiç değiştirilemeyeceği ve IsFixedSize öğesinin, koleksiyonun değişikliklere izin verdiği, ancak öğelerin eklenmesine veya kaldırılmasına izin vermediği anlamına gelir.

Net 4.5 zamanında, bazı "ara" arabirimlerin salt okunur koleksiyonlarla çalışması gerektiği açıktı IReadOnlyCollection<T>ve bu yüzden IReadOnlyList<T>tanıtıldı.

İşte ayrıntıları açıklayan harika bir blog yazısı: .NET'te salt okunur koleksiyonlar


0

IList arabiriminin tanımı, "İndeks ile ayrı ayrı erişilebilen jenerik olmayan bir nesne koleksiyonunu temsil eder." Dizi bu tanımı tamamen yerine getirir, bu yüzden arayüzü uygulamalıdır. Add () yöntemi çağrılırken kural dışı durum "System.NotSupportedException: Koleksiyon sabit bir boyuttaydı" ve dizi dinamik olarak kapasitesini artıramadığı için oluştu. Kapasitesi, dizi nesnesinin oluşturulması sırasında tanımlanır.


0

Bir dizi IList (ve geçişli olarak ICollection) uygulayan Linq2Objects motorunu basitleştirdi, çünkü IEnumerable'ı IList / ICollection'a dökmek de diziler için işe yarayacaktır.

Örneğin, bir Count () işlevi, ICollection'a verildiği ve dizinin uygulaması Uzunluk döndürdüğü için Array.Length başlığının altında çağrılır.

Bu olmadan, Linq2Objects motoru diziler için özel bir işleme sahip olmayacak ve korkunç bir performans göstermeyecek ya da diziler için özel durum tedavisi ekleyerek (IList için yaptıkları gibi) kodu ikiye katlamaları gerekecekti. Bunun yerine dizi uygulamasını IList yapmayı seçmiş olmalılar.

Bu "Neden" i benim almam.


0

Ayrıca uygulama ayrıntıları LINQ IList için son kontroller, eğer listeyi uygulamadıysa, tüm Son çağrıları yavaşlatmak için 2 kontrole ihtiyaç duyacaklar veya O (N) alan bir Dizi üzerinde Son

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.