Jakie jest uzasadnienie konwencji nazewnictwa „I” dla interfejsów w .NET?

10

Wiem, że konwencja „ja” istnieje od czasu COM, ale nigdy nie zrozumiałam, dlaczego nie została ponownie rozpatrzona, jak każda inna konwencja nazewnictwa przed .NET.

Jeśli chodzi o zużycie, jedyną rzeczą, która oddziela interfejs od, powiedzmy, klasy abstrakcyjnej, jest to, że można je wielokrotnie dziedziczyć. Ale wszystko po Visual Studio 2003 wyświetlało podpisy typu w etykietach narzędzi, więc jest tak bezużyteczne, jak wszystkie inne węgierskie notacje, które zostały odrzucone.

Pomyślałem również, że może to być tak, że możesz mieć podstawową implementację interfejsu o tej samej nazwie, np. MessageDziedziczenie IMessage, ale większość bibliotek .NET zdecydowała się na dodanie słowa „Base” na końcu (np. System.Collections.ReadOnlyCollectionBase) Zamiast - i to ma bardziej semantyczny sens.

Interoperacja COM wydaje się być kolejnym możliwym powodem - ale nie jest tak, że generowane przez nią klasy otoki są całkowicie idiomatyczne .NET, więc wątpię, aby była to uwaga estetyczna.

W jednym z moich nowych projektów całkowicie zapomniałem o konwencji i wydaje mi się, że jest w porządku. Czy czegoś brakuje?

Rei Miyasaka
źródło
1
Nie dziedziczysz interfejsów dla ich spełnienia, duża różnica.
Daniel Little
Wydaje się również, że preferencje takie jak IList i List w przeciwieństwie do List i ArrayList. Prawdopodobnie zrobili to, ponieważ IList nie jest ListBase, ale tak naprawdę jest ListInterface (nie jest listą interfejsu typu), jeśli rozumiesz.
Daniel Little
@Lavinski W .NET IListto ogólny termin na sekwencyjną, ciągłą kolekcję, losowy dostęp, podczas gdy Listjest sekwencyjną, ciągłą, losową kolekcją rosnącą . Myślę, że F # miał rację, aliasing Listdo ResizeArray; to zdecydowanie bardziej opisowa nazwa. IListto mogło być List, więc to też nie wydaje się być powodem.
Rei Miyasaka,
2
IBaseBall i IBaseBallBase mają dla mnie więcej sensu niż BaseBallBase i BaseBallBaseBase (głupi przykład, wiem: D)
e-MEE
@ e-MEE równie głupie byłoby IIRC, który może być interfejsem dla protokołu czatu IRC lub akronimem „jeśli dobrze pamiętam”.
Rei Miyasaka,

Odpowiedzi:

12

Myślę, że może to być jedyny przypadek, w którym przydatne są prefiksy.

Klasy i interfejsy naprawdę mają inną semantykę, a ponieważ oba są typami, łatwo je mieszać.
Kiedy widzę deklarację klasy, mogę natychmiast stwierdzić, z czego się wywodzi i co implementuje :

public sealed class ActivityCollection : List<Activity>, 
    IList<Activity>, ICollection<Activity>, IEnumerable<Activity>, 
    IList, ICollection, IEnumerable

Trudniej byłoby zrozumieć, jak wyglądała ta definicja

public sealed class ActivityCollection : ListClass<Activity>, 
    List<Activity>, Collection<Activity>, Enumerable<Activity>, 
    List, Collection, Enumerable

A jak byś zadzwonił ListClass? Oczywiście nie chodzi tylko o ListBaseto, że można go używać samodzielnie.
Musimy więc albo rozwiązać problem, który właśnie wynaleźliśmy, albo dostosować prefiks oddzielający klasy od interfejsów, co zrobili projektanci .NET Framework.

Ponadto osobiście uważam, że jest to przydatne, gdy mogę stwierdzić na podstawie podpisu metody, że działa z interfejsami.

public void PrintLines (IEnumerable<string> source)

To jak sygnał dla mojej głowy: hej, mogę to zaimplementować! Mogę nakarmić metodę, która pasuje do umowy.

Oczywiście można argumentować, że nie jest to takie ważne, ale jest to jedna z tych małych rzeczy, które sprawiają, że prefiks jest dla mnie tego wart. Jest to szczególnie przydatne, gdy piszesz dużo kodu z kontenerami IoC, gdy stale pracujesz z interfejsami i potrzebujesz łatwo rozróżnić oba.

Nawiasem mówiąc, nie tylko interfejsy mają prefiksy w systemie typu .NET. Nie zapomnij o ogólnych parametrach typu:

public delegate TResult Func<in T, out TResult>(
    T arg
)

Jest to kolejna sytuacja, w której niezwykle przydatne jest rozróżnienie klas i innego rodzaju typów.

Dan
źródło
2
Możesz łatwo zrozumieć, że wiedząc, że „pierwsza klasa jest dziedzictwem, druga klasa i następne są interfejsami”.
Saeed Neamati,
3
To wydaje się prawdopodobnym powodem. Java wydaje się rozwiązać go nieco bardziej przyjemnie po prostu za pomocą słów kluczowych, aby wyjaśnić listę: class Dog extends Mammal implements MailmanChaser. @ Tak, możesz mieć klasę, która niczego nie dziedziczy, więc pierwszy typ na liście to tak naprawdę interfejs, a nie klasa podstawowa.
Rei Miyasaka,
+1 dla części pogrubionej, choć mogę pomyśleć o innym miejscu, w którym pomocna byłaby konwencja oparta na prefiksach: rozróżnienie pola obejmującego wyłączną własność int[](lub innego obiektu typu zmiennego), który może mutować, ale nie share i taki, który zawiera współwłasność int[]tego, że chociaż jego typ umożliwi mutację, nikt nie może mutować.
supercat
6

Nie sądzę, żebyś niczego nie przegapił, to tylko historyczny nawyk.

Zgadzam się również z tobą i porzuciłem „ja” w kilku małych i średnich projektach bez żadnego szkodliwego efektu.

Chris Lee
źródło
2
Dziwne jest jednak to, że wyrzucili praktycznie każdą inną przestarzałą konwencję oprócz tej. Historia też tego nie tłumaczy. Nadal czuję, że musiał istnieć jakiś powód, chyba że tak naprawdę była to tylko polityka wewnętrzna - ale nawet wtedy naprawdę nie widzę powodu, dla którego ktoś byłby zdenerwowany tym, że zostałem odrzucony.
Rei Miyasaka,
2

Myślę, że jedynym powodem, zgodnie z wytycznymi Microsoft dotyczącymi nazewnictwa interfejsów i klas , jest to, że czasami masz konflikty między nazwą interfejsu a klasą, która go implementuje. Wraca to do faktu, że interfejsy to w rzeczywistości szkielet, a nie mięso, a klasa implementująca to tak naprawdę mięso (realizacja planu). Zatem IAnimal opisuje tylko to, co zwierzę powinno mieć , podczas gdy Zwierzę może ci powiedzieć, co ma .

Jednak osobiście całkowicie się z tobą zgadzam w kwestii, że moglibyśmy po prostu użyć Animal Base dla interfejsu i Animal dla klasy.

Z drugiej strony czasami dwie rzeczy są tak bardzo sprzeczne, że zespół decyduje się na konwencję, aby zapobiec dalszym konfliktom, pomimo już podjętych decyzji. Na przykład w programie ASP.NET MVC zarówno widoki częściowe , jak i układy (strony wzorcowe) są jak zwykły widok , a jednocześnie obsługują inne funkcje. Dlatego Microsoft, pomimo podkreślania, że ​​nie należy używać podkreślenia w nazewnictwie, sugeruje podkreślanie układów i widoków częściowych z podkreśleniem.

Saeed Neamati
źródło
Co w tym złego AnimalInterfacezamiast AnimalBase? To nie jest klasa podstawowa, to interfejs.
Scott Whitlock,
3
ale co jest nie tak z IAnimal zamiast AnimalInterface? na pewno przeszliśmy całą drogę do miejsca, w którym zaczęliśmy - co po prostu pokazuje, że niektóre zapisy „węgierskie” były przydatne. Wyrzucenie ich wszystkich (oprócz I i T) było bardziej pikanterią niż rozważną próbą znalezienia lepszego systemu.
gbjbaanb
2
@ScottWhitlock: Dla mnie IAnimaljest znacznie bardziej czytelny niż AnimalInterface. Preferowane są pełne nazwy, z wyjątkiem przypadków, w których można zastosować prostą, krótką konwencję dla czegoś, co występuje wystarczająco często. I takie są interfejsy.
maaartinus