Heterojen listelerin belirli bir amacı var mı?


13

Bir C # ve Java arka plan geliyor, benim listeleri homojen alışkınım ve bu bana mantıklı. Lisp'i almaya başladığımda listelerin heterojen olabileceğini fark ettim. dynamicC # anahtar kelimesi ile etrafında vida başladığımda , C # 4.0 itibariyle heterojen listeler de olabileceğini fark ettim:

List<dynamic> heterogeneousList

Benim sorum ne demek? İşlem yaparken heterojen bir listenin çok daha fazla yükü olacak gibi görünüyor ve farklı türleri bir yerde saklamanız gerekiyorsa farklı bir veri yapısına ihtiyacınız olabilir. Saflığım çirkin yüzünü mü büyütüyor yoksa heterojen bir listeye sahip olmanın faydalı olduğu zamanlar mı var?


1
Şunu mu demek istediniz ... Listelerin heterojen olabileceğini fark ettim ...?
Dünya Mühendisi

Nasıl List<dynamic>basitçe yapmaktan (Sorunuza) farklı List<object>?
Peter K.

@WorldEngineer evet, biliyorum. Yazımı güncelledim. Teşekkürler!
Jetti

@PeterK. Günlük kullanım için sanırım, hiçbir fark yok. Ancak, her C # türü System.Object türetmek değil, bu yüzden farklılıklar olduğu kenar durumlarda olurdu.
Jetti

Yanıtlar:


16

Kağıt Kesinlikle Heterojen Koleksiyonları Yazılan Oleg KISELYOV tarafından, Ralf Lammel ve Keean Schupke Haskell heterojen listelerin bir uygulama değil, aynı zamanda ne zaman, neden ve HLists nasıl kullanacağını motive edici bir örnek sadece içeriyor. Özellikle, türü güvenli derleme zamanı denetlenen veritabanı erişimi için kullanıyorlar. (LINQ, aslında, bu referans kağıt düşünün olan LINQ yol Erik Meijer ve ark Haskell kağıt).

HLists belgesinin giriş paragrafından alıntı:

İşte heterojen koleksiyonlar gerektiren tipik örneklerin açık uçlu bir listesi:

  • Farklı tipteki girişleri saklaması beklenen bir sembol tablosu heterojendir. Sonuç türünün bağımsız değişken değerine bağlı olduğu sonlu bir haritadır.
  • Bir XML öğesi heterojen olarak yazılır. Aslında, XML öğeleri normal ifadeler ve 1-belirsizlik özelliği tarafından kısıtlanan iç içe koleksiyonlardır.
  • SQL sorgusu tarafından döndürülen her satır, sütun adlarından hücrelere heterojen bir eşlemedir. Bir sorgunun sonucu, homojen bir heterojen sıra akışıdır.
  • İşlevsel bir dile gelişmiş bir nesne sistemi eklemek, genişletilebilir kayıtları alt tipleme ve numaralandırma arabirimi ile birleştiren türden heterojen koleksiyonlar gerektirir.

Sorunuzda verdiğiniz örneklerin, kelimenin yaygın olarak kullanıldığı anlamıyla heterojen listeler olmadığını unutmayın. Bunlar zayıf yazılmış veya türlenmemiş listelerdir. Aslında, tüm elemanlar aynı tipte oldukları için aslında homojen listelerdir: objectveya dynamic. Daha sonra instanceof, elemanlarla anlamlı bir şekilde çalışabilmek için onları zayıf bir şekilde yazabilmek için dökümler veya kontrolsüz testler veya bunun gibi bir şey yapmaya zorlanırsınız .


Bağlantı ve yanıtınız için teşekkürler. Listelerin gerçekten heterojen değil, zayıf yazılmış olduğuna dikkat edin. Bu yazıyı okumak için sabırsızlanıyorum (muhtemelen yarın, bu akşam ara sınavı aldım :))
Jetti

5

Uzun öykü kısa, heterojen kaplar esneklik için çalışma zamanı performansını takas eder. Belirli bir tür türü dikkate almadan bir “malzeme listesi” almak istiyorsanız, heterojenlik yoludur. Lisps karakteristik olarak dinamik olarak yazılmıştır ve her şey zaten kutulu değerlerin bir listesidir, bu nedenle ufacık performans artışı beklenir. Lisp dünyasında, programcı verimliliğinin çalışma zamanı performansından daha önemli olduğu düşünülmektedir.

Dinamik olarak yazılan bir dilde, homojen kapların aslında heterojen olanlara kıyasla hafif bir ek yükü olacaktır, çünkü eklenen tüm elemanların tip kontrolünün yapılması gerekecektir.

Daha iyi bir veri yapısı seçme konusundaki sezgileriniz yerinde. Genel olarak, kodunuz üzerinde ne kadar fazla sözleşme koyabilirsiniz, nasıl çalıştığını daha fazla bilirsiniz ve daha güvenilir, sürdürülebilir ve c. o olur. Bununla birlikte, bazen gerçekten heterojen bir kap istersiniz ve ihtiyacınız varsa bir tanesine sahip olmanıza izin verilmelidir.


1
"Ancak, bazen gerçekten heterojen bir kap istersiniz ve eğer ihtiyacınız varsa bir tanesine sahip olmanıza izin verilmelidir." - Neden olsa? Benim sorum bu. Neden bir grup veriyi rastgele bir listeye yerleştirmeniz gerekiyor?
Jetti

@Jetti: Çeşitli türlerde kullanıcı tarafından girilen ayarların bir listeniz olduğunu varsayalım. Bir arayüz oluşturabilir IUserSettingve birkaç kez uygulayabilir veya genel yapabilirsiniz UserSetting<T>, ancak statik yazmayla ilgili sorunlardan biri, tam olarak nasıl kullanılacağını bilmeden önce bir arayüz tanımlamanızdır. Tamsayı ayarlarıyla yaptığınız şeyler muhtemelen dize ayarlarıyla yaptığınız şeylerden çok farklıdır, bu nedenle hangi işlemler ortak bir arayüze koymak mantıklıdır? Kesin olana kadar, dinamik yazmayı akıllıca kullanmak ve daha sonra somut hale getirmek daha iyidir.
Jon Purdy

Sorunların olduğu yer burası. Bana göre, bu kötü bir tasarım gibi görünüyor, ne yapacağını / kullanılacağını bilmeden bir şeyler yapıyor. Ayrıca, bu durumda, arabirimi bir nesne dönüş değeri ile yapabilirsiniz. Heterojen listeyle aynı şeyi yapar, ancak arabirimde kullanılan türlerin ne olduğunu kesin olarak bildiğinizde düzeltilmesi daha net ve kolaydır.
Jetti

@Jetti: Bu aslında aynı sorun - ilk etapta evrensel bir temel sınıf olmamalı, çünkü hangi işlemleri tanımlarsa tanımlayın, bu işlemlerin mantıklı olmadığı bir tür olacaktır. Ancak C # bir objectyerine kullanmak daha kolay hale getirirse dynamic, o zaman emin, bir öncekini kullanın.
Jon Purdy

1
@Jetti: Polimorfizm bununla ilgili. Tek bir üst sınıfın alt sınıfları olmalarına rağmen listede bir dizi "heterojen" nesne bulunur. Bir Java bakış açısından, sınıf (veya arabirim) tanımlarını doğru alabilirsiniz. Diğer diller (LISP, Python, vb.) İçin, pratik uygulama farkı olmadığından, tüm bildirimleri doğru yapmanın bir yararı yoktur.
S.Lott

2

İşlevsel dillerde (lisp gibi), listedeki belirli bir öğeye ne olacağını belirlemek için desen eşleştirme kullanırsınız. C # 'daki eşdeğeri, bir öğenin türünü kontrol eden ve buna dayalı bir işlem gerçekleştiren if ... elseif deyimlerinin bir zinciri olacaktır. Söylemeye gerek yok, fonksiyonel kalıp eşleme, çalışma zamanı tip kontrolünden daha etkilidir.

Polimorfizm kullanmak, desen eşleşmesine daha yakın bir eşleşme olacaktır. Diğer bir deyişle, bir listenin nesnelerinin belirli bir arabirimle eşleşmesi ve bu arabirimde her nesne için bir işlev çağrılması. Başka bir alternatif, belirli bir nesne türünü parametre olarak alan bir dizi aşırı yüklenmiş yöntem sağlamak olacaktır. Object'i parametre olarak alan varsayılan yöntem.

public class ListVisitor
{
  public void DoSomething(IEnumerable<dynamic> list)
  {
    foreach(dynamic obj in list)
    {
       DoSomething(obj);
    }
  }

  public void DoSomething(SomeClass obj)
  {
    //do something with SomeClass
  }

  public void DoSomething(AnotherClass obj)
  {
    //do something with AnotherClass
  }

  public void DoSomething(Object obj)
  {
    //do something with everything els
  }
}

Bu yaklaşım Lisp patern eşleşmesine bir yaklaşım sağlar. Ziyaretçi kalıbı (burada uygulandığı gibi heterojen listeler için mükemmel bir kullanım örneğidir). Başka bir örnek, öncelik sırasındaki belirli mesajların dinleyicilerinin bulunduğu ve sorumluluk zincirini kullanan mesaj dağıtımına, dağıtım görevlisinin mesajı ilettiği ve mesajla eşleşen ilk işleyicinin onu ele aldığı durumdur.

Kapak tarafı, bir mesaj için kayıt yaptıran herkese bildirimde bulunur (örneğin, MVVM modelinde ViewModellerin gevşek bağlantısı için yaygın olarak kullanılan Olay Toplayıcı modeli). Aşağıdaki yapıyı kullanıyorum

IDictionary<Type, List<Object>>

Sözlüğe eklemenin tek yolu bir işlevdir

Register<T>(Action<T> handler)

(ve nesne aslında iletilen işleyiciye bir WeakReference). İşte burada <Object> Listesini kullanmak zorundayım çünkü derleme zamanında kapalı tipin ne olacağını bilmiyorum. Ancak Runtime anda sözlük için anahtar o Tür olacağını zorlayabilirsiniz. Aradığım olayı başlatmak istediğimde

Send<T>(T message)

ve listeyi tekrar çözüyorum. Listeyi <dynamic> kullanmanın bir avantajı yok çünkü zaten yayınlamam gerekiyor. Gördüğünüz gibi her iki yaklaşımın da avantajları var. Yöntem aşırı yüklemesi kullanarak bir nesneyi dinamik olarak gönderecekseniz, dinamik bunu yapmanın yoludur. Ne olursa olsun yayınlamak için ZORUNLU iseniz, Object de kullanabilirsiniz.


Örüntü eşleme ile, vakalar (genellikle - en azından ML ve Haskell'de) eşleşen veri türünün bildirimi ile taş olarak ayarlanır. Bu tür listeleri içeren listeler de heterojen değildir.

ML ve Haskell hakkında emin değilim, ancak Erlang herhangi bir şeye karşı eşleşebilir, eğer buraya ulaştıysanız, başka maçlar tatmin olmamışsa, bunu yapın.
Michael Brown

@MikeBrown - Bu güzel ama neden heterojen listeler kullanacak ve her zaman Liste <dinamik> ile çalışmaz
Jetti

4
C # 'da, aşırı yükler derleme zamanında çözülür . Böylece, sizin örnek kod olacak hep diyoruz DoSomething(Object)(kullanırken en az objectiçinde foreach; döngü dynamictamamen farklı bir şeydir).
Heinzi

@Heinzi, haklısın ... Bugün uykum var: P sabit
Michael Brown

0

Heterojenliğin çalışma zamanı yükünü taşıdığı doğrudur, ancak daha da önemlisi, daktilo makinesi tarafından sağlanan derleme zamanı garantilerini zayıflatır. Yine de, alternatiflerin daha da pahalı olduğu bazı sorunlar var.

Benim tecrübelerime göre, ham baytlarla dosyalar, ağ prizleri vb. Aracılığıyla uğraşmak, genellikle bu tür sorunlarla karşılaşırsınız.

Gerçek bir örnek vermek gerekirse, vadeli işlemleri kullanarak dağıtılmış hesaplama için bir sistem düşünün . Tek bir düğümdeki bir işçi, herhangi bir serileştirilebilir türden iş çıkarabilir ve bu tür bir geleceğe yol açabilir. Sahne arkasında, sistem işi bir eşe gönderir ve daha sonra bu iş birimini, o işin cevabı geri döndüğünde doldurulması gereken belirli bir gelecekle ilişkilendiren bir kayıt kaydeder.

Bu kayıtlar nerede saklanabilir? Sezgisel olarak, istediğiniz şey a gibi bir şeydir Dictionary<WorkId, Future<TValue>>, ancak bu sizi tüm sistemde yalnızca bir tür futures yönetmekle sınırlar. Daha uygun olan tiptir Dictionary<WorkId, Future<dynamic>>, çünkü işçi geleceği zorladığında uygun tipte döküm yapabilir.

Not : Bu örnek, alt tiplememizin olmadığı Haskell dünyasından gelir. C # 'da bu özel örnek için daha deyimsel bir çözüm varsa şaşırmam, ama umarım yine de açıklayıcıdır.


0

ISTR Lisp Eğer toplam veri nesne her türlü ihtiyacın olursa, o gidiyor, bir liste dışındaki herhangi bir veri yapılarını yok olması heterojen bir liste olması. Diğerlerinin de belirttiği gibi, iletim veya depolama için verileri serileştirmek için de kullanışlıdır. Güzel bir özellik de açık uçlu olmalarıdır, böylece bunları bir boru ve filtreler benzetmesine dayanan bir sistemde kullanabilir ve sabit bir veri nesnesi veya iş akışı topolojisi gerektirmeden ardışık işleme adımlarını artırabilir veya düzeltebilirsiniz. .

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.