Jenerik suistimal nedir?


35

Bazı kodları incelerken, jenerik kullanmak için onu değiştirme fırsatını fark ettim. (Gizlenmiş) kodu şöyle görünür:

public void DoAllTheThings(Type typeOfTarget, object[] possibleTargets)
{
    var someProperty = typeOfTarget.GetProperty(possibleTargets[0]);
    ...
}

Bu kod şöyle, jeneriklerle değiştirilebilir:

public void DoAllTheThings<T>(object[] possibleTargets[0])
{
    var someProperty = type(T).getProperty(possibleTargets[0]);
    ...
}

Bu yaklaşımın yararlarını ve eksikliklerini araştırırken genel istismarı adı verilen bir terim buldum . Görmek:

Sorum iki bölümden oluşuyor:

  1. Bunun gibi jenerik ilaçlara geçmenin bir faydası var mı? (Performans? Okunabilirlik?)
  2. Jenerik Kötüye Kullanım Nedir? Ve her seferinde bir tür parametresi kötüye kullanımı olduğunda bir genel kullanıyor mu?

2
Kafam karıştı. Özelliğin adını önceden biliyorsunuz, ancak nesnenin türünü değil, bu nedenle bir değer elde etmek için yansıma kullanıyorsunuz?
MetaFight

3
@MetaFight Bunun kıvrımlı bir örnek olduğunu biliyorum, gerçek kod buraya koymak uzun ve zor olurdu. Ne olursa olsun, sorumun amacı, Type parametresini bir jenerikle değiştirmenin iyi mi yoksa kötü bir form olarak mı değerlendirileceğini belirlemektir.
SyntaxRules

12
Her zaman jeneriklerin var olmasının tipik bir nedeni olduğunu düşünmüştüm (lezzetli pansuman amaçlanmadı). Yazı sisteminizi sizin için yapması için neden kaldırabiliyorsanız, neden yazı tipini kendiniz kandırıyorsunuz?
MetaFight

2
Örnegin tuhaf, ama bir sürü IoD kütüphanesinin tam olarak ne yaptığını hissediyorum
Ewan

14
Cevap değil, ikinci örneğin birincisinden daha az esnek olduğuna dikkat çekiyor. İşlevin genel olması, bir çalışma zamanı türüne geçme yeteneğinizi ortadan kaldırır; Jeneriklerin derleme sırasındaki türü bilmeleri gerekir.
KChaloux

Yanıtlar:


87

Jenerikler uygun şekilde uygulandığında, sadece yeniden düzenlemek yerine kodu kaldırırlar . Öncelikle, jeneriklerin kaldırılmasında en iyisi olan kod, yazım işaretleri, yansıma ve dinamik yazımdır. Bu nedenle, jenerik kötüye kullanımı, jenerik olmayan bir uygulamaya kıyasla, tahmin, yansıtma veya dinamik yazmada önemli bir azalma olmadan genel kod oluşturma olarak tanımlanabilir.

Örneğinizle ilgili olarak, jeneriklerin object[]a T[]ya da benzerini değiştirmesi ve bundan kaçınması Typeya da typetamamen kullanılması için uygun bir jenerik kullanımı beklerdim . Bu, başka yerlerde önemli yeniden düzenleme gerektirebilir, ancak jenerik kullanmak bu durumda uygunsa, işiniz bittiğinde genel olarak daha kolay sonuçlanmalıdır.


3
Bu harika bir nokta. Bunu bana düşündüren kodun yansımayı okumak için biraz zor olduğunu itiraf edeceğim. Degisebilirim eğer görürsünüz object[]için T[].
SyntaxRules

3
Kaldırmayı yeniden düzenleme karakterizasyonunu seviyorum.
copper.hat

13
Jeneriklerin bir anahtar kullanımını kaçırdınız - bu da çoğaltmayı azaltmak. (Bahsettiğiniz diğer günahlardan herhangi birini tanıtarak çoğaltmayı azaltabilirsiniz). Herhangi bir yazı tipi, yansıma veya dinamik yazı IMO'sunu kaldırmadan çoğaltmayı azaltırsa, tamamdır.
Michael Anderson,

4
Mükemmel cevap Bunu eklerdim. Bu özel durumda, OP'nin jenerikler yerine bir arayüze geçmesi gerekebilir . Yansıma, nesnenin belirli özelliklerine erişmek için kullanılıyor gibi görünüyor; Bir arayüz derleyicinin bu özelliklerin gerçekten var olduğunu tespit etmesine izin vermek için çok daha uygundur.
jpmc26

4
@MichaelAnderson "sadece yeniden düzenlemek yerine kodu kaldır", çoğaltmayı azaltmayı da içeriyor
Caleth

5

Saçma sapan kuralını kullanırdım: Jenerik, diğer tüm programlama yapıları gibi, bir sorunu çözmek için var olur . Jenerikler için çözülecek bir sorun yoksa, bunları kullanmak kötüyedir.

Belirli jenerik durumlarda, çoğunlukla farklı türlerin kod uygulamalarının tek bir genel şablonda (ya da diliniz ne olursa olsun) bir araya getirilmesine izin vererek somut türlerden uzaklaşmak için soyutlar. Şimdi, bir tür kullanan kodun olduğunu varsayalım Foo. Bu türü bir jenerikle değiştirebilirsiniz T, ancak çalışmak için yalnızca bu koda ihtiyacınız olursa Foo, birlikte katlayabileceğiniz başka bir kod yoktur. Bu nedenle, çözülecek bir problem yoktur, bu nedenle jenerik katmanın indirilmesi sadece okunabilirliği azaltmaya hizmet edecektir.

Sonuç olarak, kodları jenerik kullanmadan, yazmanız gerekene kadar (sadece ikinci bir örneğe ihtiyaç duyduğunuz için) yazmanızı öneririm. Sonra, ve ancak o zaman, jenerik kullanımı için kodu yeniden düzenleme zamanı geldi. Bu noktadan önceki herhangi bir kullanım gözlerimde suistimaldir.


Bu biraz bilgiçlik gibi görünüyor, bu yüzden size hatırlatmama izin verin:
Programlamada istisnalar olmadan hiçbir kural yoktur. Bu kural dahil edildi.


İlginç düşünceler. Ancak, kriterlerinizin hafif bir şekilde yeniden değerlendirilmesi yardımcı olabilir. OP'nin bir dizgeye bir int eşleyen ve bunun tersi olan yeni bir "bileşen" e ihtiyacı olduğunu varsayalım. Ortak bir ihtiyacı çözdüğü ve gelecekte jenerik hale getirildiği takdirde kolayca yeniden kullanılabileceği çok açıktır. Bu durum, jenerik kötüye kullanımı tanımınıza düşecektir. Bununla birlikte, çok genel altta yatan ihtiyaç tespit edildiğinde, bu bir istismar olmadan tasarımda önemsiz bir ek çaba harcamak değmez mi?
Christophe

@ Christophe Bu gerçekten zor bir soru. Evet, kuralımı görmezden gelmenin gerçekten daha iyi olduğu bazı durumlar vardır (programlamada istisna olmadan kural yoktur!). Bununla birlikte, belirli bir dize dönüşüm durumu aslında oldukça karmaşıktır: 1. İmzalı ve işaretsiz tamsayı tiplerini ayrı ayrı ele almanız gerekir. 2. Kayan nokta dönüşümlerine tamsayı dönüşümlerinden ayrı davranmanız gerekir. 3. Daha küçük tipler için mevcut en büyük tamsayı türleri için bir uygulamayı yeniden kullanabilirsiniz. Proaktif olarak döküm yapmak için genel bir sarıcı yazmak isteyebilirsiniz, ancak çekirdek jenerik olmadan olacaktır.
cmaster

1
Proaktif olarak genel bir YAGNI olarak (yeniden kullanım yerine kullanım öncesi) bir jenerik yazmaya karşı savunuyorum. İhtiyacınız olduğunda, sonra refactor.
Neil_UK

Bu soruyu yazdıktan sonra "Gelecekte olası yeniden kullanımı kurtarmak için mümkünse jenerik olarak yazın." Bunun biraz aşırı olduğunu biliyordum. Burada bakış açınızı görmek çok güzel. Teşekkürler!
SyntaxRules

0

Kod tuhaf görünüyor. Ancak, biz onu çağırıyorsak, türü bir genel olarak belirtmek daha hoş görünür.

https://stackoverflow.com/questions/10955579/passing-just-a-type-as-a-parameter-in-c-sharp

Şahsen arama kodunun hoş görünmesini sağlayan bu sıkışmaları sevmiyorum. örneğin bütün 'akıcı' şey ve Uzatma Yöntemleri.

Ancak bunun popüler bir takip olduğunu kabul etmek zorundasınız. microsoft bile örneğin birlik içinde kullanmak

container.RegisterType<IInterface,Concrete>()

0

Bana göre burada doğru yoldaydın, ama işi bitirmedim.

object[]Parametreyi bir Func<T,object>[]sonraki adım için değiştirmeyi düşündünüz mü ?

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.