Dlaczego wszystkie klasy w .NET globalnie dziedziczą po klasie Object?

16

Jest to dla mnie bardzo interesujące, którego zalety dają „globalną klasę root” dla frameworka. Krótko mówiąc, jakie były przyczyny tego, że środowisko .NET zostało zaprojektowane tak, aby miało jedną klasę obiektów głównych z ogólną funkcjonalnością odpowiednią dla wszystkich klas.

Obecnie projektujemy nową platformę do użytku wewnętrznego (platforma w ramach platformy SAP) i wszyscy podzieliliśmy się na dwa obozy - pierwszy, który uważa, że ​​ten szkielet powinien mieć globalny katalog główny, a drugi - kto myśli inaczej.

Jestem na obozie „Global root”. A moje powody, jakie to podejście zapewniłoby dobrą elastyczność i redukcję kosztów rozwoju, ponieważ nie będziemy już rozwijać ogólnej funkcjonalności.

Jestem więc bardzo zainteresowany, aby dowiedzieć się, jakie powody skłaniają architektów .NET do takiego projektowania ram.

Anton Semenov
źródło
6
Pamiętaj, że .NET Framework jest częścią uogólnionego środowiska programistycznego. Bardziej szczegółowe struktury, takie jak Twoja, mogą nie potrzebować obiektu „root”. W objectsystemie .NET istnieje po części root, ponieważ zapewnia on pewne podstawowe możliwości dla wszystkich obiektów, takich jak ToString()iGetHashCode()
Robert Harvey
10
„Jestem bardzo interesujący, aby dowiedzieć się, jakie powody skłaniają architektów .NET do takiego projektowania ram”. Istnieją trzy bardzo dobre powody: 1. Java zrobiła to w ten sposób, 2. Java zrobiła to w ten sposób i 3. Java zrobiła to w ten sposób.
dasblinkenlight
2
@vcsjones: i Java na przykład już zanieczyszczone przez wait()/ notify()/ notifyAll()i clone().
Joachim Sauer,
3
@daskblinkenlight Thats poo. Java nie zrobiła tego w ten sposób.
Dante
2
@dasblinkenlight: FYI, Java to ta, która obecnie kopiuje C #, z lambdami, funkcjami LINQ itp.
user541686

Odpowiedzi:

18

Najbardziej palącą przyczyną Objectsą pojemniki (przed lekami generycznymi), które mogą zawierać cokolwiek zamiast iść w stylu C „Napisz to wszystko, czego potrzebujesz”. Oczywiście, pomysł, że wszystko powinno odziedziczyć po określonej klasie, a następnie nadużywanie tego faktu, aby całkowicie stracić każdą plamkę bezpieczeństwa typu, jest tak straszny, że powinien być gigantyczną lampką ostrzegawczą przed wysyłką języka bez leków generycznych, a także oznacza że Objectjest dokładnie redundantny dla nowego kodu.

DeadMG
źródło
6
To jest właściwa odpowiedź. Jedynym powodem był brak ogólnego wsparcia. Inne argumenty „wspólnych metod” nie są prawdziwymi argumentami, ponieważ wspólne metody nie muszą być wspólne - Przykład: 1) ToString: nadużywane w większości przypadków; 2) GetHashCode: w zależności od tego, co robi program, większość klas nie potrzebuje tej metody; 3) GetType: nie musi być metodą instancji
Codism
2
W jaki sposób .NET „całkowicie gubi każdą plamkę bezpieczeństwa typu”, „nadużywając” idei, że wszystko powinno odziedziczyć po określonej klasie? Czy jest jakiś kod shit, który można napisać Object, a którego nie można by napisać void *w C ++?
Carson63000,
3
Kto powiedział, że myślałem, że void*jest coś lepszego? To nie jest Jeśli cokolwiek. jest jeszcze gorzej .
DeadMG,
void*jest gorszy w C ze wszystkimi niejawnymi rzutami wskaźnika, ale C ++ jest bardziej rygorystyczny pod tym względem. Przynajmniej musisz rzucić jawnie.
Tamás Szelei,
2
@fish: Sprzeczność terminologiczna: w C nie ma czegoś takiego jak „niejawna obsada”. Rzutowanie jest jawnym operatorem, który określa konwersję. Masz na myśli „niejawne konwersje wskaźnika ”.
Keith Thompson
11

Pamiętam, jak kiedyś Eric Lippert powiedział, że dziedziczenie po System.Objectklasie zapewnia „najlepszą wartość dla klienta”. [edytuj: tak, powiedział to tutaj ]:

... Nie potrzebują wspólnego typu podstawowego. Tego wyboru nie dokonano z konieczności. Powstało z chęci zapewnienia najlepszej wartości dla klienta.

Projektując system typów lub cokolwiek innego pod tym względem, czasami dochodzisz do punktów decyzyjnych - musisz zdecydować X lub nie-X ... Korzyści z posiadania wspólnego typu podstawowego przeważają koszty, a tym samym korzyść netto naliczona kwota jest większa niż korzyść netto z braku wspólnego wspólnego rodzaju. Dlatego wybieramy wspólny typ podstawowy.

To dość niejasna odpowiedź. Jeśli chcesz uzyskać bardziej szczegółową odpowiedź, spróbuj zadać bardziej szczegółowe pytanie.

Posiadanie wszystkiego, co wywodzi się z System.Objectklasy, zapewnia niezawodność i użyteczność, którą bardzo szanowałem. Wiem, że wszystkie obiekty będą miały typ ( GetType), że będą zgodne z metodami finalizacji CLR ( Finalize) i że mogę GetHashCodez nich korzystać podczas obsługi kolekcji.

gws2
źródło
2
To jest wadliwe. Nie potrzebujesz GetType, możesz po prostu rozszerzyć, typeofaby zastąpić jego funkcjonalność. Jeśli chodzi o to Finalize, w rzeczywistości wiele typów nie jest w ogóle finalizowalnych i nie ma sensownej metody finalizacji. Ponadto wiele typów nie jest haszowalnych ani konwertowalnych na ciąg znaków - szczególnie typy wewnętrzne, które nigdy nie są przeznaczone do takich celów i nigdy nie są udostępniane do użytku publicznego. Wszystkie te typy mają niepotrzebnie zanieczyszczone interfejsy.
DeadMG,
5
Nie, to nie jest wadliwy - nigdy nie twierdził, że należałoby użyć GetType, Finalizelub GetHashCodedla każdego System.Object. Powiedziałem tylko, że są tam, jeśli ich chcesz. Jeśli chodzi o „ich niepotrzebnie zanieczyszczone interfejsy”, odniosę się do mojego pierwotnego cytatu elippert: „najlepsza wartość dla klienta”. Oczywiście zespół .NET był gotów poradzić sobie z kompromisami.
gws2
Jeśli nie jest to konieczne, oznacza to zanieczyszczenie interfejsu. „Jeśli chcesz” nigdy nie jest dobrym powodem do włączenia metody. Powinien tam być tylko dlatego, że go potrzebujesz, a Twoi konsumenci go nazywają . W przeciwnym razie nie jest dobrze. Również twój cytat Lipperta stanowi apel do błędnego autorytetu, ponieważ nie mówi on nic innego jak „to dobrze”.
DeadMG,
Nie próbuję argumentować twoich argumentów @DeadMG - pytanie dotyczyło konkretnie: „Dlaczego wszystkie klasy w .NET globalnie dziedziczą od klasy Object” i dlatego podłączyłem do poprzedniego postu przez osobę bardzo blisko zespołu .NET w Microsoft, który udzielił uzasadnionej - choć niejasnej - odpowiedzi na pytanie, dlaczego zespół programistów .NET wybrał to podejście.
gws2
Zbyt niejasne, aby być odpowiedzią na to pytanie.
DeadMG,
4

Myślę, że projektanci Java i C # dodali obiekt root, ponieważ był on dla nich w zasadzie darmowy, jak na darmowym obiedzie .

Koszty dodania obiektu głównego są bardzo równe kosztom dodania pierwszej funkcji wirtualnej. Ponieważ zarówno CLR, jak i JVM są środowiskami śmieciowymi z finalizatorami obiektów, musisz mieć co najmniej jeden wirtualny dla twojej java.lang.Object.finalizelub dla twojej System.Object.Finalizemetody. W związku z tym koszty dodania obiektu głównego są już opłacone, możesz uzyskać wszystkie korzyści bez płacenia za to. To jest najlepsze z obu światów: użytkownicy, którzy potrzebują wspólnej klasy root, dostaną to, czego chcą, a użytkownicy, którym nie zależy to mniej, będą mogli programować tak, jakby ich nie było.

dasblinkenlight
źródło
4

Wydaje mi się, że masz tutaj trzy pytania: jedno dotyczy tego, dlaczego wspólny root został wprowadzony do .NET, drugie to zalety i wady tego, a trzecie to, czy dobrym pomysłem jest, aby element ramowy miał globalny korzeń.

Dlaczego .NET ma wspólny katalog główny?

W najbardziej technicznym sensie posiadanie wspólnego pierwiastka jest niezbędne dla odbicia i dla pojemników pre-generycznych.

Ponadto, o ile mi wiadomo, posiadanie wspólnego katalogu głównego z metodami podstawowymi, takimi jak equals()i hashCode()został bardzo pozytywnie odebrany w Javie, a na C # miał wpływ (między innymi) Java, więc chcieli mieć tę funkcję również.

Jakie są zalety i wady posiadania wspólnego katalogu głównego w języku?

Zaleta posiadania wspólnego katalogu głównego:

  • Możesz zezwolić wszystkim obiektom na działanie określonych funkcji, które uważasz za ważne, takie jak equals()i hashCode(). Oznacza to na przykład, że każdy obiekt w Javie lub C # może być używany w mapie skrótu - porównaj tę sytuację z C ++.
  • Możesz odwoływać się do obiektów nieznanych typów - np. Jeśli po prostu przenosisz informacje, tak jak zrobiły to pojemniki pre-ogólne.
  • Możesz odnosić się do obiektów niepoznawalnego typu - np. Podczas korzystania z odbicia.
  • Może być używany w rzadkich przypadkach, gdy chcesz być w stanie zaakceptować obiekt, który może być innego i niepowiązanego typu - np. Jako parametr printfmetody podobnej do.
  • Zapewnia elastyczność zmiany zachowania wszystkich obiektów przez zmianę tylko jednej klasy. Na przykład, jeśli chcesz dodać metodę do wszystkich obiektów w programie C #, możesz dodać metodę rozszerzenia do object. Być może niezbyt powszechne, ale bez wspólnego korzenia nie byłoby to możliwe.

Wada posiadania wspólnego katalogu głównego:

  • Może być nadużywane w odniesieniu do obiektu o pewnej wartości, nawet jeśli mógłbyś użyć do tego bardziej dokładnego typu.

Czy powinieneś korzystać ze wspólnego katalogu głównego w swoim projekcie ramowym?

Oczywiście bardzo subiektywnie, ale kiedy spojrzę na powyższą listę pro-conów, zdecydowanie odpowiem tak . W szczególności ostatni punkt na liście pro - elastyczność późniejszej zmiany zachowania wszystkich obiektów przez zmianę katalogu głównego - staje się bardzo przydatny na platformie, na której zmiany w katalogu głównym są częściej akceptowane przez klientów niż zmiany całej język.

Poza tym - choć jest to jeszcze bardziej subiektywne - uważam, że koncepcja wspólnego korzenia jest bardzo elegancka i pociągająca. Ułatwia także korzystanie z niektórych narzędzi, na przykład teraz można łatwo poprosić narzędzie, aby pokazało wszystkich potomków tego wspólnego katalogu głównego i otrzymało szybki, dobry przegląd typów frameworka.

Oczywiście typy muszą być do tego co najmniej nieznacznie powiązane, aw szczególności nigdy nie poświęciłbym zasady „jest”, aby mieć wspólny rdzeń.

Dąb
źródło
Myślę, że Java nie miała wpływu na c #, ale w pewnym momencie była - Java. Microsoft nie mógł już używać Javy, więc straciłby miliardy na inwestycjach. Zaczęli od podania języka, że ​​mają już nową nazwę.
Mike Braun
3

Matematycznie bardziej elegancko jest mieć system typów zawierający top i pozwalający na pełniejsze zdefiniowanie języka.

Jeśli tworzysz framework, rzeczy z pewnością zostaną zużyte przez istniejącą bazę kodu. Nie możesz mieć uniwersalnego nadtypu, ponieważ istnieją wszystkie inne typy, niezależnie od tego, co zużywa framework.

W tym momencie decyzja o wspólnej klasie bazowej zależy od tego, co robisz. Bardzo rzadko zdarza się, że wiele rzeczy ma wspólne zachowanie i przydatne jest odwoływanie się do tych rzeczy za pomocą samego wspólnego zachowania.

Ale to się zdarza. Jeśli tak, to od razu wyodrębnij to wspólne zachowanie.

Telastyn
źródło
2

Przekazano obiekt główny, ponieważ chcieli, aby wszystkie klasy w ramach obsługiwały pewne rzeczy (uzyskanie kodu skrótu, konwersja na ciąg znaków, kontrole równości itp.). Zarówno C #, jak i Java uznają za przydatne umieszczenie wszystkich tych wspólnych funkcji Object w jakiejś klasie root.

Pamiętaj, że nie naruszają one żadnych zasad OOP ani niczego. Wszystko w klasie Object ma sens w dowolnej podklasie (czytaj: dowolna klasa) w systemie. Jeśli zdecydujesz się przyjąć ten projekt, upewnij się, że postępujesz zgodnie z tym wzorem. Oznacza to, że nie należy umieszczać w katalogu głównym rzeczy, które nie należą do każdej pojedynczej klasy w systemie. Jeśli dokładnie przestrzegasz tej zasady, nie widzę żadnego powodu, dla którego nie powinieneś mieć klasy root, która zawiera użyteczny, wspólny kod dla całego systemu.

Oleksi
źródło
2
To wcale nie jest prawda. Istnieje wiele klas przeznaczonych wyłącznie do użytku wewnętrznego, które nigdy nie są mieszane, nigdy się nad nimi nie zastanawiają, nigdy nie są konwertowane na ciąg. Niepotrzebne spadków i metody zbędnych zdecydowanie nie naruszać wiele zasad.
DeadMG,
2

Kilka powodów, wspólna funkcjonalność, którą mogą udostępniać wszystkie klasy potomne. Dało to także twórcom frameworka możliwość napisania wielu innych funkcji do frameworka, z których wszystko mogłoby korzystać. Przykładem może być buforowanie i sesje ASP.NET. Prawie wszystko może być w nich przechowywane, ponieważ napisali metody dodawania do akceptowania obiektów.

Klasa root może być bardzo pociągająca, ale bardzo, bardzo łatwo ją niewłaściwie wykorzystać. Czy zamiast tego można mieć interfejs użytkownika root? I masz tylko jedną lub dwie małe metody? A może dodałoby to o wiele więcej kodu niż jest to wymagane w twoim systemie?

Pytam, jestem ciekawy, jaką funkcjonalność musisz udostępnić wszystkim możliwym klasom w pisanym frameworku. Czy to naprawdę wykorzystają wszystkie obiekty? Lub przez większość z nich? A kiedy utworzysz klasę root, jak zapobiegniesz dodawaniu do niej losowych funkcji? Lub zmienne losowe, które chcą być „globalne”?

Kilka lat temu była bardzo duża aplikacja, w której utworzyłem klasę root. Po kilku miesiącach opracowywania został wypełniony kodem, w którym nie było biznesu. Konwertowaliśmy starą aplikację ASP, a klasa główna zastąpiła stary plik global.inc, którego używaliśmy w przeszłości. Musiałem nauczyć się tej lekcji na własnej skórze.

bwalk2895
źródło
2

Wszystkie autonomiczne obiekty sterty dziedziczą Object; ma to sens, ponieważ wszystkie autonomiczne obiekty sterty muszą mieć pewne wspólne aspekty, takie jak sposób identyfikacji ich typu. W przeciwnym razie, jeśli śmieciarz miałby odwołanie do obiektu sterty nieznanego typu, nie miałby możliwości dowiedzenia się, jakie bity w obiekcie blob pamięci związanym z tym obiektem powinny być traktowane jako odniesienia do innych obiektów sterty.

Ponadto w systemie typów wygodnie jest używać tego samego mechanizmu do definiowania elementów struktur i elementów klas. Zachowanie lokalizacji pamięci typu wartości (zmiennych, parametrów, pól, miejsc tablic itp.) Jest bardzo różne od lokalizacji pamięci typu klasy, ale takie różnice behawioralne są osiągane w kompilatorach kodu źródłowego i silniku wykonawczym (w tym kompilator JIT), a nie wyrażany w systemie typów.

Jedną z konsekwencji tego jest to, że zdefiniowanie typu wartości skutecznie definiuje dwa typy - typ lokalizacji magazynu i typ obiektu sterty. Pierwsze z nich może być domyślnie przekonwertowane na drugie, a drugie może zostać przekonwertowane na pierwsze za pomocą typecastu. Oba typy konwersji działają poprzez kopiowanie wszystkich pól publicznych i prywatnych z jednej instancji danego typu do drugiej. Ponadto możliwe jest użycie ogólnych ograniczeń do bezpośredniego wywoływania elementów interfejsu w lokalizacji pamięci typu wartość, bez uprzedniego wykonania jej kopii.

Wszystko to jest ważne, ponieważ odwołania do obiektów sterty typu wartości zachowują się jak odwołania do klas, a nie jak typy wartości. Rozważmy na przykład następujący kod:

string testEnumerator <T> (T it) gdzie T: IEnumerator <łańcuch>
{
  var it2 = it;
  it.MoveNext ();
  it2.MoveNext ();
  return it.Current;
}
publiczny test nieważności ()
{
  var theList = new List <string> ();
  theList.Add („Fred”);
  theList.Add („George”);
  theList.Add („Percy”);
  theList.Add („Molly”);
  theList.Add („Ron”);

  var enum1 = theList.GetEnumerator ();
  IEnumerator <string> enum2 = enum1;

  Debug.Print (testEnumerator (enum1));
  Debug.Print (testEnumerator (enum1));
  Debug.Print (testEnumerator (enum2));
  Debug.Print (testEnumerator (enum2));
}

Jeśli testEnumerator()metoda zostanie przekazana, miejsce przechowywania typu wartości itotrzyma instancję, której pola publiczne i prywatne zostaną skopiowane z przekazanej wartości. Zmienna lokalna it2przechowa inną instancję, z której wszystkie pola zostaną skopiowane it. Dzwoniąc MoveNextna it2nie wpłynie it.

Jeśli powyższy kod zostanie przekazany do miejsca przechowywania typu klasy, wówczas przekazana wartość iti it2wszystkie będą odnosić się do tego samego obiektu, a zatem wywołanie MoveNext()dowolnego z nich spowoduje skuteczne wywołanie go na wszystkich z nich.

Zauważ, że rzutowanie w List<String>.Enumeratorcelu IEnumerator<String>skutecznego przekształca go z typu wartości na typ klasy. Typ obiektu sterty jest, List<String>.Enumeratorale jego zachowanie będzie się bardzo różnić od typu wartości o tej samej nazwie.

supercat
źródło
+1 za brak wzmianki o ToString ()
JeffO
1
Chodzi o szczegóły implementacji. Nie ma potrzeby udostępniania ich użytkownikowi.
DeadMG,
@DeadMG: Co masz na myśli? Obserwowalne zachowanie tego, List<T>.Enumeratorktóry jest przechowywany jako a, List<T>.Enumeratorznacznie różni się od zachowania tego, które jest przechowywane w tym IEnumerator<T>, że przechowywanie wartości poprzedniego typu w miejscu przechowywania dowolnego typu utworzy kopię stanu modułu wyliczającego, podczas zapisywania wartości tego drugiego typu w miejscu przechowywania, które również jest tego drugiego typu, nie utworzy kopii.
supercat
Tak, ale nieObject ma to nic wspólnego z tym faktem.
DeadMG,
@DeadMG: Chodzi mi o to, że instancja typu sterty System.Int32jest również instancją typu System.Object, ale lokalizacja pamięci typu System.Int32nie zawiera ani System.Objectinstancji, ani odwołania do niej.
supercat
2

Ten projekt naprawdę nawiązuje do Smalltalk, co w dużej mierze uważałbym za próbę orientacji na obiekt kosztem niemal wszystkich innych problemów. Jako taki, moim zdaniem, ma tendencję do używania orientacji obiektowej, nawet jeśli inne techniki są prawdopodobnie (a nawet na pewno) lepsze.

Posiadanie jednej hierarchii z Object(lub czymś podobnym) w katalogu głównym sprawia, że ​​dość łatwe (na przykład) tworzenie klas kolekcji jako kolekcji jest Objectwięc banalne, aby kolekcja zawierała dowolny rodzaj obiektu.

W zamian za tę raczej niewielką przewagę dostajesz wiele wad. Po pierwsze, z punktu widzenia projektu, masz naprawdę szalone pomysły. Co, zgodnie z poglądem Java na wszechświat, co łączy ateizm i las? Oboje mają kody skrótu! Czy mapa to kolekcja? Według Javy nie, nie jest!

W latach 70., kiedy projektowano Smalltalk, tego rodzaju bzdury zostały zaakceptowane, przede wszystkim dlatego, że nikt nie opracował rozsądnej alternatywy. Smalltalk został sfinalizowany w 1980 r., A do 1983 r. Opracowano Adę (która obejmuje generyczne). Chociaż Ada nigdy nie osiągnęła takiej popularności, jaką niektórzy przewidywali, jej ogólne cechy były wystarczające do obsługi zbiorów obiektów dowolnych typów - bez szaleństwa nieodłącznego od monolitycznych hierarchii.

Kiedy zaprojektowano Javę (i, w mniejszym stopniu, .NET), monolityczną hierarchię klas prawdopodobnie postrzegano jako „bezpieczny” wybór - z problemami, ale najczęściej znanymi problemami. Natomiast programowanie ogólne było takie, które prawie wszyscy (nawet wtedy) zdawało sobie sprawę, było przynajmniej teoretycznie znacznie lepsze podejście do problemu, ale takie, które wielu komercyjnych deweloperów uważało za raczej słabo zbadane i / lub ryzykowne (tj. W świecie komercyjnym , Ada została w dużej mierze odrzucona jako porażka).

Pozwólcie, że wyrażę się jasno: monolityczna hierarchia była błędem. Przyczyny tego błędu były co najmniej zrozumiałe, ale i tak był to błąd. To zły projekt, a jego problemy projektowe przenikają prawie cały kod, który go używa.

W przypadku nowego projektu nie ma jednak rozsądnego pytania: stosowanie monolitycznej hierarchii jest oczywistym błędem i złym pomysłem.

Jerry Coffin
źródło
Warto stwierdzić, że szablony były znane i przydatne przed dostarczeniem platformy .NET.
DeadMG,
W świecie komercyjnym, Ada była awaria, nie tyle ze względu na jego szczegółowość, ale ze względu na brak standaryzacji interfejsów do usług systemu operacyjnego. Brak standardowego interfejsu API dla systemu plików, grafiki, sieci itp. Sprawił, że tworzenie aplikacji hostowanych przez Ada było niezwykle kosztowne.
kevin cline
@kevincline: Prawdopodobnie powinienem to sformułować nieco inaczej - z tego powodu, że Ada jako całość została odrzucona jako porażka z powodu swojej porażki na rynku. Odmowa użycia Ady była (IMO) dość rozsądna - ale odmowa uczenia się od niej znacznie mniej (w najlepszym wypadku).
Jerry Coffin
@Jerry: Myślę, że szablony C ++ przyjęły ideę generycznych Ady, a następnie znacznie je ulepszyły z domyślną instancją.
kevin cline
1

To, co chcesz zrobić, jest naprawdę interesujące, trudno jest udowodnić, czy jest źle, czy dobrze, dopóki nie skończysz.

Oto kilka rzeczy do przemyślenia:

  • Kiedy miałbyś kiedykolwiek celowo przekazywać ten obiekt najwyższego poziomu nad bardziej konkretny obiekt?
  • Jaki kod zamierzasz umieścić w każdej ze swoich klas?

Są to jedyne dwie rzeczy, które mogą czerpać korzyści ze wspólnego katalogu głównego. W języku służy do zdefiniowania kilku bardzo powszechnych metod i umożliwia przekazywanie obiektów, które nie zostały jeszcze zdefiniowane, ale nie powinny mieć zastosowania.

Ponadto z własnego doświadczenia:

Użyłem kiedyś zestawu narzędzi napisanego przez programistę, którego tłem było Smalltalk. Sprawił, że wszystkie jego klasy „Data” rozszerzyły jedną klasę, a wszystkie metody zajęły tę klasę - jak dotąd tak dobrze. Problem polega na tym, że różne klasy danych nie zawsze były wymienne, więc teraz mój edytor i kompilator nie mógł udzielić ŻADNEJ pomocy co do tego, co należy przejść do danej sytuacji, i musiałem odwołać się do jego dokumentów, które nie zawsze pomagały. .

To była najtrudniejsza w użyciu biblioteka, z jaką kiedykolwiek miałem do czynienia.

Bill K.
źródło
0

Ponieważ taka jest metoda OOP. Ważne jest, aby mieć typ (obiekt), który może odnosić się do wszystkiego. Argument typu obiekt może zaakceptować wszystko. Istnieje również dziedziczenie, możesz być pewien, że ToString (), GetHashCode () itp. Są dostępne na wszystkim i wszystkim.

Nawet Oracle zdało sobie sprawę ze znaczenia takiego podstawowego typu i planuje usunięcie prymitywów w Javie pod koniec 2017 roku

Dante
źródło
6
Nie jest to ani droga OOP, ani ważne. Nie podajesz żadnych rzeczywistych argumentów oprócz „Jest dobrze”.
DeadMG,
1
@DeadMG Możesz przeczytać argumenty za pierwszym zdaniem. Prymitywy zachowują się inaczej niż obiekty, co zmusza programistę do napisania wielu wariantów kodu tego samego celu dla obiektów i prymitywów.
Dante,
2
@DeadMG dobrze powiedział, że oznacza to, że możesz założyć ToString()i GetType()będzie na każdym obiekcie. Prawdopodobnie warto zauważyć, że można użyć zmiennej typu objectdo przechowywania dowolnego obiektu .NET.
JohnL
Ponadto jest całkowicie możliwe napisanie typu zdefiniowanego przez użytkownika, który może zawierać odniesienie dowolnego typu. Aby to osiągnąć, nie potrzebujesz specjalnych funkcji językowych.
DeadMG,
Powinieneś mieć obiekt tylko na poziomach, które zawierają określony kod, nigdy nie powinieneś mieć go tylko do powiązania wykresu. „Obiekt” w rzeczywistości implementuje kilka ważnych metod i działa jako sposób na przekazanie obiektu do oprzyrządowania, w którym ten typ jeszcze nawet nie został stworzony.
Bill K