W jednym z naszych projektów jest dużo kodu, który wygląda następująco:
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (s == null)
{
return "Foo";
}
return $({s}Foo);
}
}
Czy jest jakiś wyraźny powód, aby to zrobić inaczej niż „łatwiej jest upublicznić ten typ później?”
Podejrzewam, że ma to znaczenie tylko w bardzo dziwnych przypadkach na krawędziach (odbicie w Silverlight) lub wcale.
return s + "Foo";
?+
Operator nie dba o null lub pustych strunach.Odpowiedzi:
AKTUALIZACJA: To pytanie było przedmiotem mojego bloga we wrześniu 2014 r . Dzięki za świetne pytanie!
Trwa debata na ten temat, nawet w samym zespole kompilatorów.
Po pierwsze, dobrze jest zrozumieć zasady. Publiczny członek klasy lub struktury to członek, który jest dostępny dla wszystkiego, co może uzyskać dostęp do typu zawierającego . Publiczny członek klasy wewnętrznej jest więc efektywnie wewnętrzny.
Czy teraz, biorąc pod uwagę klasę wewnętrzną, jej członkowie, do których chcesz uzyskać dostęp w zgromadzeniu, powinni być oznaczeni jako publiczni czy wewnętrzni?
Moja opinia jest taka: oznacz takich członków jako publiczną.
Używam słowa „public”, co oznacza, że „ten członek nie jest szczegółem implementacji”. Chroniony członek jest szczegółem implementacji; jest coś w tym, co będzie potrzebne, aby klasa pochodna działała. Element wewnętrzny jest szczegółem implementacji; coś innego wewnętrznego w tym zespole potrzebuje członka, aby działać poprawnie. Członek publiczny mówi: „ten członek reprezentuje kluczową, udokumentowaną funkcjonalność zapewnianą przez ten obiekt”.
Zasadniczo mam takie podejście: załóżmy, że postanowiłem przekształcić tę klasę wewnętrzną w klasę publiczną. Aby to zrobić, chcę zmienić dokładnie jedno : dostępność klasy. Jeśli przekształcenie klasy wewnętrznej w klasę publiczną oznacza, że muszę również przekształcić członka wewnętrznego w członka publicznego, wówczas ten członek był częścią publicznego obszaru klasy i powinien był być przede wszystkim publiczny.
Inni ludzie się nie zgadzają. Istnieje kontyngent, który mówi, że chcą móc rzucić okiem na deklarację członka i od razu wiedzieć, czy będzie wywoływana tylko z kodu wewnętrznego.
Niestety nie zawsze działa to dobrze; na przykład klasa wewnętrzna, która implementuje interfejs wewnętrzny, nadal musi mieć elementy implementujące oznaczone jako publiczne, ponieważ są one częścią publicznej powierzchni klasy .
źródło
public
jest bardzo przekonujący. Uważam jednak, że „nie zawsze dobrze się układa ...” jest szczególnie silny. Utrata spójności dewaluuje wszelkie korzyści „na pierwszy rzut oka”. Używanieinternal
w ten sposób oznacza celowe budowanie intuicji, które czasem są błędne. Posiadanie w większości właściwej intuicji jest IMO okropną rzeczą do programowania.Jeśli klasa jest
internal
, nie ma znaczenia z punktu widzenia dostępności, czy oznaczysz metodęinternal
czypublic
. Jednak nadal dobrze jest użyć typu, którego użyłbyś, gdyby klasa byłapublic
.Podczas gdy niektórzy powiedzieli, że to ułatwia przejście od
internal
dopublic
. Służy również jako część opisu metody.Internal
metody są zwykle uważane za niebezpieczne dla nieskrępowanego dostępu, podczas gdypublic
metody są uważane za (głównie) darmową grę.Używając
internal
lubpublic
tak, jak napublic
zajęciach, upewniasz się, że komunikujesz, jaki styl dostępu jest oczekiwany, jednocześnie ułatwiając pracę wymaganą do stworzenia klasypublic
w przyszłości.źródło
Często zaznaczam moje metody w klasach wewnętrznych jako publiczne zamiast wewnętrznych jako a) to naprawdę nie ma znaczenia i b) używam wewnętrznego, aby wskazać, że metoda jest wewnętrzna celowo (istnieje jakiś powód, dla którego nie chcę tego ujawniać metoda w klasie publicznej. Dlatego jeśli mam metodę wewnętrzną, naprawdę muszę zrozumieć powód, dla którego jest ona wewnętrzna, zanim zmienię ją na publiczną, natomiast jeśli mam do czynienia z metodą publiczną w klasie wewnętrznej, naprawdę muszę pomyśleć, dlaczego klasa jest wewnętrzna, w przeciwieństwie do tego, dlaczego każda metoda jest wewnętrzna.
źródło
Podejrzewam, że „łatwiej jest później upublicznić ten typ?” czy to jest
Reguły określania zakresu oznaczają, że metoda będzie widoczna tylko jako
internal
- więc naprawdę nie ma znaczenia, czy metody są oznaczone,public
czy teżinternal
.Jedną z możliwości, które przychodzą na myśl, jest to, że klasa była publiczna, a później została zmieniona na,
internal
a programista nie zadał sobie trudu, aby zmienić wszystkie modyfikatory dostępności metody.źródło
W niektórych przypadkach może być również tak, że typ wewnętrzny implementuje interfejs publiczny, co oznaczałoby, że wszelkie metody zdefiniowane w tym interfejsie nadal będą musiały zostać zadeklarowane jako publiczne.
źródło
Tak samo, metoda publiczna będzie naprawdę oznaczona jako wewnętrzna, ponieważ znajduje się w klasie wewnętrznej, ale ma tę zaletę (jak gościłeś), jeśli chcesz oznaczyć klasę jako publiczną, musisz zmienić mniej kodu.
źródło
internal
mówi, że do członka można uzyskać dostęp tylko z tego samego zespołu. Inne klasy w tym zestawie mogą uzyskiwać dostęp dointernal public
elementu, ale nie będą miały dostępu do elementuprivate
lubprotected
elementu,internal
lub nie.źródło
internal
zamiastpublic
, ich widoczność nie zmieniłaby się. Uważam, że o to pyta OP.Naprawdę walczyłem z tym dzisiaj. Do tej pory powiedziałbym, że wszystkie metody powinny być naznaczone,
internal
gdyby klasa byłainternal
i rozważałaby coś innego po prostu złe kodowanie lub lenistwo, szczególnie w rozwoju przedsiębiorstw; musiałem jednak podklasowaćpublic
klasę i zastąpić jedną z jej metod:Metoda MUSI być
public
i sprawiło, że pomyślałem, że naprawdę nie ma logicznego sensu ustalania metod,internal
chyba że tak naprawdę musi być, jak powiedział Eric Lippert.Do tej pory nigdy tak naprawdę nie zastanawiałem się nad tym, po prostu to zaakceptowałem, ale po przeczytaniu posta Erica naprawdę mnie to zastanowiło i po wielu rozważaniach ma to sens.
źródło
Jest różnica. W naszym projekcie wprowadziliśmy wiele klas wewnętrznych, ale przeprowadzamy testy jednostkowe w innym zestawie, aw naszych informacjach o zespole użyliśmy InternalsVisibleTo, aby umożliwić zespołowi UnitTest wywoływanie klas wewnętrznych. Zauważyłem, że jeśli klasa wewnętrzna ma konstruktora wewnętrznego, z jakiegoś powodu nie jesteśmy w stanie utworzyć instancji za pomocą Activator.CreateInstance w zestawie testów jednostkowych. Ale jeśli zmienimy konstruktor na publiczny, ale klasa jest nadal wewnętrzna, działa dobrze. Ale wydaje mi się, że jest to bardzo rzadki przypadek (jak Eric powiedział w oryginalnym poście: Odbicie).
źródło
Myślę, że mam na ten temat dodatkową opinię. Na początku zastanawiałem się, w jaki sposób sens ogłosić coś publicznie w klasie wewnętrznej. Skończyłem tutaj, czytając, że może być dobrze, jeśli później zdecydujesz się zmienić klasę na publiczną. Prawdziwe. Tak więc w moim umyśle powstał wzór : jeśli to nie zmieni obecnego zachowania, to bądźcie tolerancyjni i dopuszczajcie rzeczy, które nie mają sensu (i nie ranią) w obecnym stanie kodu, ale później tak by było, gdybyście zmień deklarację klasy.
Lubię to:
Zgodnie z „wzorem”, o którym wspomniałem powyżej, powinno to być całkowicie w porządku. Wynika to z tego samego pomysłu. Zachowuje się jak
private
metoda, ponieważ nie można dziedziczyć klasy. Ale jeśli usunieszsealed
ograniczenie, nadal będzie ważne: odziedziczone klasy zobaczą tę metodę, co absolutnie chciałem osiągnąć. Ale pojawia się ostrzeżenie:CS0628
lubCA1047
. Obaj nie zamierzają deklarowaćprotected
członków wsealed
klasie. Co więcej, doszedłem do pełnej zgody, że nie ma sensu: ostrzeżenie „Członek chroniony w zapieczętowanej klasie” (klasa singletona)Więc po tym ostrzeżeniu i połączonej dyskusji postanowiłem uczynić wszystko wewnętrznym lub mniejszym, w klasie wewnętrznej, ponieważ bardziej odpowiada temu rodzajowi myślenia i nie mieszamy różnych „wzorów”.
źródło