Neden bir iç sınıfta genel bir yöntem kullanılır?


250

Projelerimizden birinde şöyle görünen bir sürü kod var:

internal static class Extensions
{
    public static string AddFoo(this string s)
    {
        if (s == null)
        {
            return "Foo";
        }

        return $({s}Foo);
    }
}

Bunu yapmanın "türü daha sonra herkese açık hale getirmek daha kolay" dışında herhangi bir açık nedeni var mı?

Ben sadece çok garip kenar durumlarda (Silverlight yansıma) önemli ya da hiç önemli değil.


1
Deneyimlerime göre, bu normal bir uygulamadır.
phoog

2
@foog, tamam. ama neden normal bir uygulama? Belki bir grup yöntemi dahili olarak değiştirmekten daha kolay? Hızlı düzeltme -> tipi dahili olarak işaretlemek ister misiniz?
bopapa_1979

hep böyle varsaydım. Ancak, iyi düşünülmüş bir analizim yok, bu yüzden bir cevap göndermedim.
phoog

2
Eric Lippert'in cevabı düşüncemi çok iyi özetliyor ve ayrıca bir çıkış yolu bulmaya çalışan beynimde gizlenen bir şeyi ortaya koyuyor: arayüz üyelerinin örtük uygulamaları kamuya açık olmalı.
phoog

Bu yöntem eşit değil return s + "Foo";mi? +Operatör boş veya boş dizeleri umursamıyor.
Mikkel R. Lund

Yanıtlar:


419

GÜNCELLEME: Bu soru Eylül 2014'teki blogumun konusuydu . Bu mükemmel soru için teşekkürler!

Derleyici ekibinin kendisinde bile bu soru üzerine önemli tartışmalar var.

Öncelikle kuralları anlamak akıllıca olur. Bir sınıfın veya yapının genel üyesi , içeren türe erişebilen her şeye erişebilen bir üyedir . Dolayısıyla, bir iç sınıfın kamu üyesi etkili bir şekilde içseldir.

Şimdi, bir iç sınıf verildiğinde, mecliste erişmek istediğiniz üyeleri herkese açık mı, yoksa dahili mi olarak işaretlenmeli?

Benim düşüncem: bu tür üyeleri halka açık olarak işaretlemek.

"Herkese açık bir uygulama değil" demek için "genel" kullanıyorum. Korunan bir üye uygulama detayıdır; türetilmiş bir sınıfın çalışması için gerekli olan bir şey var. Dahili üye bir uygulama detayıdır; bu meclisin içindeki başka bir şeyin düzgün çalışması için üyeye ihtiyacı vardır. Herkese açık bir üye "bu üye, bu nesne tarafından sağlanan temel, belgelenmiş işlevselliği temsil eder."

Temel olarak benim tutumum: varsayalım ki bu iç sınıfı bir kamu sınıfına dönüştürmeye karar verdim. Bunu yapmak için, tam olarak bir şeyi değiştirmek istiyorum : sınıfın erişilebilirliği. Eğer bir iç sınıfı bir genel sınıfa dönüştürmek demek, bir iç üyeyi de genel bir üyeye dönüştürmek zorunda olduğum anlamına gelirse, o üye sınıfın ortak yüzey alanının bir parçasıydı ve ilk etapta halka açık olması gerekirdi.

Diğer insanlar aynı fikirde değil. Bir üyenin beyanına bakmak istediklerini ve sadece dahili koddan çağrılıp çağrılmayacağını derhal bildiklerini söyleyen bir koşul vardır.

Ne yazık ki, bu her zaman iyi sonuç vermez; örneğin, bir iç arabirimi uygulayan bir iç sınıfın hala uygulayıcı üyelerin halka açık olarak işaretlenmesi gerekir, çünkü bunlar sınıfın kamusal yüzeyinin bir parçasıdır .


11
Bu yanıtı seviyorum ... mümkün olan en yüksek düzeyde kendi kendini belgeleyen kod yazma konusundaki tutumumla iyi uyuyor ve kapsam, özellikle diğer ekip üyeleriniz sözleşmenizi anlıyorsa, niyet yayınlamak için harika bir yoldur.
bopapa_1979

10
Söylemek istediklerimi söylemek için +1 ancak yapabildiğimden çok daha iyi formüle etmek için (aynı zamanda arayüz açısını ortaya çıkarmak için, ancak bunun sadece örtülü üye uygulamaları için doğru olduğunu not ediyorum).
phoog

2
Arayüz kısmı önemlidir - dahili bir arayüz yöntemi uygulamak imkansızdır, açık veya açık arayüz beyanıdır. Yani kamu kelimesi iki anlamla aşırı yüklüdür.
Michael Stum

8
Düşünsel bir bakış açısından, lehinize yaptığınız argüman publicçok inandırıcıdır. Ancak, "her zaman iyi çalışmaz ..." özellikle güçlü buluyorum. Tutarlılığı kaybetmek, "bir bakışta" faydaları düşürür. internalBu şekilde kullanmak kasıtlı olarak bazen yanlış olan sezgiler oluşturmak anlamına gelir. Çoğunlukla doğru bir sezgiye sahip olmak, IMO'yu programlama için korkunç bir şeydir.
Brian

3
Blog gönderinizden önemli alıntı: "Tavsiyem, ekibiniz arasındaki sorunu tartışmak, bir karar vermek ve daha sonra buna bağlı kalmaktır."
1717

17

Sınıf ise internal, bir yöntemi işaretlemeniz internalveya işaretlememeniz bir erişilebilirlik açısından önemli değildir public. Ancak, sınıf olsaydı kullanacağınız türü kullanmak hala iyidir public.

Bazı bundan geçişleri kolaylaştırır söylediler iken internaletmek public. Aynı zamanda yöntemin açıklamasının bir parçası olarak hizmet eder. Internalyöntemler genellikle serbest erişim için güvensiz kabul edilirken, publicyöntemler (çoğunlukla) ücretsiz oyun olarak kabul edilir.

Kullanarak internalya publicgibi bir yer olurdu publicsınıfta, size de sınıf yapmak için gerekli çalışmayı kolaylaştırırken erişimin tarzı, beklenenleri iletişim sağlamak publicgelecekte.


İyi bir API oluştururken ve hedeflediğim tüketicinin yapmayı düşündüğüm şeyi yapmasına izin verirken her şeyi mümkün olan en üst düzeyde sınırlama eğilimindeyim. Sınıf herkese açık olsaydı, üyeyi işaretlediğim gibi de sizinle birlikteyim. Daha spesifik olarak, her zaman güvenli olduğunu düşünürsem, herhangi bir üyeyi herkese açık olarak işaretlerim. Aksi takdirde, daha sonra sınıfı halka işaretleyen başka biri güvenli olmayan üyeleri ortaya çıkarabilir.
bopapa_1979

@Eric: Hazır olana kadar bir yöntemin güvenliğini belirlemeyi bırakmak istiyorsanız, bu iyi, ancak sadece güvenli kabul edilen yöntemlere atıfta bulunuyordum, bu durumda maruz kalma yok.
Guvante

10

Yöntemlerimi içsel olarak sınıflar dışında içsel olarak işaretlerim a) gerçekten önemli değil ve b) içsel olarak yöntemin bilerek içsel olduğunu belirtmek için kullanıyorum (bunu ortaya çıkarmak istemememin bir nedeni var) Bu nedenle, içsel bir yöntemim varsa, bunu genel olarak değiştirmeden önce neden içsel olduğunu anlamak zorundayken, bir iç sınıfta genel bir yöntemle uğraşıyorsam gerçekten nedenini düşünmek zorundayım. sınıf, her yöntemin neden içsel olduğu yerine içseldir.


Cevap için teşekkürler.
İnatla

1
Doğru söylüyorsun Eric, bu biraz uzak bir yorum oldu. Umarım cevabımın geri kalanı bir işe yarar. Eric Lippert'in cevabı anlatmaya çalıştığım şeydi ama çok daha iyi açıkladı.
Ɖiamond ǤeezeƦ

8

"Türü daha sonra herkese açık hale getirmek daha mı kolay?" bu mu.

Kapsam belirleme kuralları, yöntemin yalnızca şu şekilde görünür olacağı anlamına gelir internal- bu nedenle, yöntemlerin işaretlenmiş publicveya işaretlenmemiş olması gerçekten önemli değildir internal.

Akla gelen bir olasılık sınıfı olmasıdır oldu kamu ve daha sonra değiştirildi internalve geliştirici tüm yöntem erişilebilirlik değiştiricileri değiştirmeye rahatsız etmedi.


1
Açık olan "kamu sınıfı içselleşti" senaryosunu çivilemek için +1.
bopapa_1979

8

Bazı durumlarda, dahili türün genel bir arabirim uygulaması da olabilir; bu, bu arabirimde tanımlanan herhangi bir yöntemin yine de genel olarak bildirilmesi gerektiği anlamına gelir.



0

internalüyeye yalnızca aynı meclisten erişilebileceğini söylüyor. Bu derlemedeki diğer sınıflar internal publicüyeye erişebilir , ancak bir privateveya protectedüyeye erişemez veya erişemez internal.


Ancak internalbunun yerine yöntemler işaretlenirse public, görünürlüğü değişmezdi. OP'nin bunu sorduğuna inanıyorum.
Oded

1
@zapthedingbat - gönderi aslında doğrudur, ancak aslında soruyu cevaplıyor mu?
Oded

1
Doğru, soru NEDEN onları bu şekilde işaretlemek. Kapsamın temellerini anlıyorum. Yine de girişim için teşekkürler!
bopapa_1979

0

Aslında bugün bununla mücadele ettim. Şimdiye kadar internal, sınıfın internal, özellikle de kurumsal gelişimde, sadece kötü kodlama veya tembellik gibi başka bir şey olduğunu düşünür ve düşünürsek, yöntemlerin hepsinin işaretlenmesi gerektiğini söyleyebilirdim ; Ancak, bir publicsınıfın alt sınıf ve yöntemlerinden birini geçersiz kılmak zorunda kaldı :

internal class SslStreamEx : System.Net.Security.SslStream
{
    public override void Close()
    {
        try
        {
            // Send close_notify manually
        }
        finally
        {
            base.Close();
        }
    }
}

Metod OLMALIDIR publicve internalEric Lippert'in dediği gibi, metodları gerçekten olmadıkları sürece ayarlamanın gerçekten mantıklı bir noktası olmadığını düşündürdü.

Şimdiye kadar bunu düşünmeyi hiç bırakmadım, sadece kabul ettim, ama Eric'in gönderisini okuduktan sonra gerçekten düşünmemi sağladı ve çok fazla tartışmanın ardından çok mantıklı.


0

Bir fark var. Projemizde çok fazla sınıf oluşturduk, ancak başka bir montajda birim testi yapıyoruz ve montaj bilgilerimizde UnitTest montajının dahili sınıfları çağırmasına izin vermek için InternalsVisibleTo kullandık. İç sınıf bir iç yapıcı varsa fark ettim, nedense Activator.CreateInstance kullanarak birim oluşturmak için örnek oluşturamıyoruz montaj. Ancak yapıcıyı kamuya çevirirsek, ancak sınıf hala içselse, iyi çalışır. Ama sanırım bu çok nadir bir durum (Eric'in orijinal yazıda söylediği gibi: Yansıma).


0

Sanırım bu konuda ek bir fikrim var. İlk başta, bir iç sınıfta halka bir şeyler bildirmenin nasıl mantıklı olduğunu merak ediyordum. Sonra buraya geldim, daha sonra sınıfı halka açmaya karar vermenin iyi olabileceğini okudum. Doğru. Yani, aklımda oluşan bir desen : Mevcut davranışı değiştirmezse, o zaman izin verici olun ve geçerli kod durumunda mantıklı olmayan (ve incitmeyen) şeylere izin verin, ancak daha sonra, sınıfın bildirisini değiştirir.

Bunun gibi:

public sealed class MyCurrentlySealedClass
{
    protected void MyCurretlyPrivateMethod()
    {
    }
}

Yukarıda bahsettiğim "kalıba" göre, bu gayet iyi olmalı. Aynı fikri izler. privateSınıfı devralmadığınız için bir yöntem gibi davranır . Ancak sealedkısıtlamayı silerseniz , yine de geçerlidir: miras alınan sınıflar bu yöntemi görebilir, ki bu kesinlikle elde etmek istediğim şeydi. Ancak bir uyarı alırsınız: CS0628veya CA1047. Her ikisi de protectedbir sealedsınıfta üye ilan etmemekle ilgilidir . Dahası, anlamsız olduğu konusunda tam bir mutabakat buldum: 'Mühürlü sınıfta korunan üye' uyarısı (tek sınıf)

Bu uyarı ve tartışma bağlantılandıktan sonra, her şeyi içsel veya daha az, içsel bir sınıfta yapmaya karar verdim, çünkü bu tür bir düşünceye daha çok uyuyor ve farklı "kalıpları" karıştırmıyoruz.


Eric Lippert bunu büyük ölçüde yapmayı tercih ediyorum (veya en azından nedenlerle). Makalesi kesinlikle okunmaya değer.
bopapa_1979
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.