Jenerikler nasıl uygulanır?


16

Derleyici iç perspektifinden gelen soru budur.

Ben jenerikler, şablonlar (C ++) ile ilgilenmiyorum, bu yüzden soruyu C # ile işaretledim. Java değil, çünkü AFAIK her iki dildeki jenerikler uygulamalarda farklılık göstermektedir.

Jenerik olmayan dillere baktığımda oldukça basit, sınıf tanımını doğrulayabilir, hiyerarşiye ekleyebilir ve hepsi bu.

Fakat genel sınıfla ne yapmalı ve daha da önemlisi, ona referansları nasıl ele alalım? Her örnek için statik alanların tekil olduğundan nasıl emin olunur (yani, genel parametreler her çözüldüğünde).

Diyelim ki bir çağrı görüyorum:

var x = new Foo<Bar>();

Foo_BarHiyerarşiye yeni bir sınıf ekleyebilir miyim ?


Güncelleme: Şimdiye kadar sadece 2 alakalı gönderi buldum, ancak "kendiniz nasıl yapılır" anlamında çok fazla ayrıntıya girmiyorlar:


Olumlu oylama çünkü tam bir cevabın ilginç olacağını düşünüyorum. Nasıl çalıştığı hakkında bazı fikirlerim var ama doğru cevaplamak için yeterli değil. C # jenerikleri her genel türü için özel sınıflar için derlemek sanmıyorum. Çalışma zamanında çözülmüş gibi görünüyorlar (jenerikleri kullanmaktan gözle görülür bir hız olabilir). Belki Eric Lippert'in içeri girmesini sağlayabiliriz?
KChaloux

2
@KChaloux: MSIL düzeyinde jenerik için bir açıklama var. JIT çalıştığında, genel parametreler olarak kullanılan her bir değer türü için ayrı bir makine kodu ve tüm referans türlerini kapsayan bir makine kodu kümesi daha oluşturur. MSIL'de genel açıklamayı korumak gerçekten güzel çünkü çalışma zamanında yeni örnekler oluşturmanıza izin veriyor.
Ben Voigt

@Ben Bu yüzden aslında soruyu cevaplamaya çalışmadım: p
KChaloux

Eğer hala buralarda olup olmadığından emin değilim, ama hangi dili size derleme için . Bunun jenerikleri nasıl uyguladığınız üzerinde büyük etkisi olacaktır. Genellikle ön uçta nasıl yaklaştığım hakkında bilgi verebilirim, ancak arka uç çılgınca değişebilir.
Telastyn

@Telastyn, bu konular için emin ben :-) Ben, gerçekten yakın C # için bir şey arıyorum am benim durumumda ben derleme am için PHP (şaka). Bilginizi paylaşırsanız minnettar olacağım.
greenoldman

Yanıtlar:


4

Her örnek için statik alanların tekil olduğundan nasıl emin olunur (yani, genel parametreler her çözüldüğünde).

Her genel örneklemenin, statik alanların depolandığı (kafa karıştırıcı olarak adlandırılmış) MethodTable'ın kendi bir kopyası vardır.

Diyelim ki bir çağrı görüyorum:

var x = new Foo<Bar>();

Foo_BarHiyerarşiye yeni bir sınıf ekleyebilir miyim ?

Sınıf hiyerarşisini aslında çalışma zamanında var olan bazı yapı olarak düşünmenin yararlı olduğundan emin değilim, daha mantıklı bir yapı.

Ancak, bu hiyerarşiyi oluşturmak için her biri temel sınıfına dolaylı bir işaretçi olan MethodTables'ı düşünürseniz, evet, bu hiyerarşiye yeni bir sınıf ekler.


Teşekkür ederim, bu ilginç bir parça. Yani statik alanlar sanal tabloya benzer şekilde çözülür, değil mi? Her tür giriş için "global" sözlüğe referans var mı? Böylece birbirlerini bilmeyen 2 meclisim olabilir Foo<string>ve iki statik alan örneği üretmezler Foo.
greenoldman

1
@greenoldman Sanal tabloya benzer şekilde değil, tamamen aynı. MethodTable, hem statik alanları hem de sanal dağıtımda kullanılan tür yöntemlerine başvuruları tutar (bu nedenle MethodTable olarak adlandırılır). Ve evet, CLR'nin tüm MethodTable'lara erişmek için kullanabileceği bir tablo olması gerekir.
svick

2

Orada iki gerçek somut soru görüyorum. Tam olarak anlayabilmek için muhtemelen ilgili diğer soruları sormak istersiniz (buna geri bağlantı içeren ayrı bir soru olarak).

Statik alanlara genel örnek başına nasıl ayrı örnekler verilir?

Genel tür parametreleriyle ilgili olmayan statik üyeler için bu oldukça kolaydır (genel parametrelerden değere eşlenen bir sözlük kullanın).

Tür parametreleriyle ilişkili üyeler (statik ya da değil) tür silme yoluyla işlenebilir. En güçlü kısıtlama ne olursa olsun kullanın (genellikle System.Object). Tür bilgisi derleyici türü denetimlerinden sonra silindiğinden, çalışma zamanı türü denetimlerine gerek kalmayacağı anlamına gelir (arabirim yayınları çalışma zamanında hala mevcut olsa da).

Her genel örnek tür hiyerarşisinde ayrı olarak görünüyor mu?

.NET jeneriklerinde değil. Devralmanın tür parametrelerinden çıkarılmasına karar verildi, bu nedenle bir jenerikin tüm örneklerinin tür hiyerarşisinde aynı noktayı işgal ettiği ortaya çıktı.

Bu muhtemelen iyi bir karardı, çünkü bir temel sınıftan isimlere bakmamak inanılmaz derecede şaşırtıcı olurdu.


Benim sorunum, şablon açısından düşünmekten kurtulamamam. Örneğin - aksine şablon jenerik sınıf olduğunu tam olarak derlenmiş. Bu, bu sınıfı kullanan diğer mecliste ne olur? Zaten derlenmiş yöntem dahili döküm ile çağrılır? I jenerik kısıt güvenebilir şüphe - yerine değişken, aksi takdirde Foo<int>ve Foo<string>aynı veri çarpar Fooo / w kısıtlar.
greenoldman

1
@greenoldman: Aslında özel olarak ele alındıklarından bir dakika boyunca değer türlerinden kaçınabilir miyiz? Varsa List<string>ve List<Form>sonra List<T>dahili olarak bir tür üyesi olduğundan T[]ve üzerinde herhangi bir kısıtlama olmadığından T, aslında alacağınız şey, bir manipüle eden makine kodudur object[]. Bununla birlikte, Tdiziye yalnızca örnekler konulduğundan, çıkan her şey Tek bir tür denetimi olmadan bir olarak döndürülebilir . Öte yandan, eğer olsaydı ControlCollection<T> where T : Control, dahili dizi T[]haline gelirdi Control[].
Ben Voigt

Kısıtlamanın dahili tip adı olarak alındığını ve kullanıldığını doğru anladım, ancak sınıf gerçekten kullanıldığında, döküm kullanılıyor mu? Tamam, bu modeli anlıyorum, ama Java'nın C # değil, kullandığı izlenimindeydim.
greenoldman

3
@greenoldman: Java, kaynak-> bayt kodu çeviri adımında tür silme işlemini gerçekleştirir. Bu, doğrulayıcının genel kodu doğrulamasını imkansız hale getirir. C # bayt kodu-> makine kodu adımında yapar.
Ben Voigt

@BenVoigt Bazı türler Java'da genel türler hakkında tutulur, aksi halde kaynağı olmadan genel kullanan bir sınıfa karşı derleme yapamazsınız. Sadece bayt kodu dizisinin kendisinin AIUI'sinde değil, daha çok sınıf meta verilerinde tutulur.
Donal Fellows

1

Fakat genel sınıfla ne yapmalı ve daha da önemlisi, ona referansları nasıl ele alalım?

Derleyicinin ön ucundaki genel yol, genel tür ( List<T>) ve bağlı genel tür ( List<Foo>) olmak üzere iki tür tür örneğine sahip olmaktır . Genel tür hangi işlevlerin var olduğunu, hangi alanları tanımladığını ve nerede Tkullanılırsa kullanılsın genel tür referanslarına sahiptir . Bağlı genel tür, genel türe bir başvuru ve bir tür bağımsız değişken kümesi içerir. Bu, daha sonra genel tür referanslarını Fooveya tür bağımsız değişkenlerini değiştirerek somut bir tür oluşturmanız için yeterli bilgiye sahiptir . Bu tür bir ayrım, tür çıkarımı yaparken ve buna List<T>karşı çıkarım yapmanız gerektiğinde önemlidir List<Foo>.

Şablonlar (genel olarak çeşitli uygulamaları oluşturan) gibi jenerikleri düşünmek yerine, bunları işlevsel dil tipi yapıcıları gibi düşünmek yararlı olabilir (burada genel argümanlar size bir tür veren bir işleve argümanlar gibidir).

Arka tarafa gelince, gerçekten bilmiyorum. Jeneriklerle ilgili tüm çalışmalarım CIL'i arka uç olarak hedefledi, bu yüzden onları orada desteklenen jeneriklere derleyebildim.


Çok teşekkür ederim (yazık cevapları kabul edemiyorum). Bu adımı hemen hemen doğru bir şekilde yaptığımı duymak harika - benim durumumda List<T>gerçek tip (tanımı) tutarken, List<Foo>(terminoloji parçası için de teşekkür ederim) yaklaşımımla List<T>(elbette şimdi bağlı) Fooyerine T).
greenoldman
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.