Klasy a moduły w VB.NET

157

Czy dopuszczalną praktyką jest używanie modułów zamiast klas ze współdzielonymi funkcjami składowymi w VB.NET?

Staram się unikać modułów, ponieważ wydaje się, że pozostały resztki z Visual Basic 6.0 i tak naprawdę nie pasują już do nich. Z drugiej strony wydaje się, że nie ma dużej różnicy między używaniem modułu a klasą z tylko współdzielonymi członkami. Nie jest tak często, że naprawdę potrzebuję ich, ale czasami zdarzają się sytuacje, w których stanowią one proste rozwiązanie.

Jestem ciekawy, czy masz jakieś zdanie lub preferencje w taki czy inny sposób.

Tom Juergens
źródło
10
Ciekawostką dotyczącą modułów jest to, że domyślnie metody i funkcje zadeklarowane wewnątrz mają poziom ochrony modułu, co oznacza, że ​​możesz nieumyślnie udostępnić metody, jeśli zapomnisz jawnie dodać Privatekwalifikator. W klasie domyślnym poziomem ochrony jest prywatny, co może być mylące, jeśli nie jesteś tego świadomy.
yu_ominae

Odpowiedzi:

207

Modules są odpowiednikami VB staticklas C # . Gdy Twoja klasa jest zaprojektowana wyłącznie dla funkcji pomocniczych i metod rozszerzających i nie chcesz zezwalać na dziedziczenie i tworzenie instancji , używasz rozszerzenia Module.

Nawiasem mówiąc, używanie Modulenie jest tak naprawdę subiektywne i nie jest przestarzałe . Rzeczywiście, musisz użyć, Modulekiedy jest to właściwe. Sama .NET Framework robi to wiele razy ( System.Linq.Enumerablena przykład). Aby zadeklarować metodę rozszerzenia, wymagane jest użycie Modules.

Mehrdad Afshari
źródło
7
Całkiem dobrze, chociaż mogę użyć prywatnego konstruktora, aby zapobiec tworzeniu instancji i modyfikatora NotInheritable. Nieco brzydszy niż zwykły stary moduł, ale daje ten sam efekt. Dzięki za wskazówkę do korzystania z modułów we frameworku; Przyjrzę się temu.
Tom Juergens
8
Pod maską są one po prostu kompilowane do klas z atrybutem [StandardModule]. Ponadto korzystanie z modułu zmusza Cię do tego, aby nie mieć tam rzeczy, które nie są udostępnione, co jest dobre.
Mehrdad Afshari
18
Moduły nie są tym samym, co klasy statyczne w języku C #. Metody w module są efektywnie globalne, jeśli znajdują się w zaimportowanej przestrzeni nazw.
JaredPar
2
@JaredPar: Moje sformułowanie jest prawdopodobnie złe. Powinienem był powiedzieć odpowiedniki VB klas statycznych C #. Na podstawie tego stwierdzenia chciałem powiedzieć, że używanie modułu ma sens w przypadku pisania klasy statycznej w C #.
Mehrdad Afshari
3
@Chiwda Zobacz msdn.microsoft.com/en-us/library/bb384936.aspx : „Metody rozszerzające można deklarować tylko w modułach”.
Mehrdad Afshari,
34

Myślę, że dobrym pomysłem jest unikanie modułów, chyba że umieścisz je w oddzielnych przestrzeniach nazw. Ponieważ w Intellisense metody w modułach będą widoczne z każdego miejsca w tej przestrzeni nazw.

Więc zamiast tego kończysz ModuleName.MyMethod()z MyMethod()wyskakującymi okienkami w dowolnym miejscu i ten rodzaj unieważnia hermetyzację. (przynajmniej na poziomie programowania).

Dlatego zawsze staram się tworzyć klasę metodami współdzielonymi, wydaje się o wiele lepsza.

dr. zło
źródło
7
Zgoda, pracuję w tej chwili na starym programie (prawdopodobnie port VB6 na VB.NET 1) z klasami i modułami. Istnieją setki globalnych zmiennych, podrzędnych i funkcji w około dziesięciu różnych modułach i piekło jest dowiedzieć się, skąd się wzięło i jak zostało zmodyfikowane.
yu_ominae
ok, to jest bardzo stare, ale dotyczy mojego pytania. Jestem nie VB facet, ale mam z nim pracować. Próbuję rozbić dużą klasę (> 46 000 wierszy), ponieważ IntelliSense / ReSharper po prostu umiera. Odkryłem, że używam modułów i po prostu zgrywanie dużych fragmentów funkcji do ich własnego modułu wydaje się działać, ale zastanawiam się, czy powinienem również nadać każdemu modułowi własną przestrzeń nazw. Czy to byłoby konieczne? tj. czy przyspieszyłoby to technologię IntelliSense tylko dzięki modułom, czy też przestrzenie nazw pomogłyby bardziej?
codah
27

Moduły nie są w żadnym wypadku przestarzałe i są intensywnie używane w języku VB. Jest to na przykład jedyny sposób na zaimplementowanie metody rozszerzającej w VB.Net.

Istnieje jedna ogromna różnica między modułami a klasami ze statycznymi składnikami. Każda metoda zdefiniowana w module jest dostępna globalnie, o ile moduł jest dostępny w bieżącej przestrzeni nazw. W efekcie moduł umożliwia definiowanie metod globalnych. To jest coś, czego nie może zrobić klasa, w której są tylko współdzieleni członkowie.

Oto krótki przykład, którego często używam podczas pisania kodu VB, który współdziała z surowymi interfejsami COM.

Module Interop
  Public Function Succeeded(ByVal hr as Integer) As Boolean
    ...
  End Function

  Public Function Failed(ByVal hr As Integer) As Boolean
    ...
  End Function
End Module

Class SomeClass
  Sub Foo()
    Dim hr = CallSomeHrMethod()
    if Succeeded(hr) then
      ..
    End If
  End Sub
End Class
JaredPar
źródło
4
Metody rozszerzeń ... kolejna dobra funkcja, której zawsze chcę używać, ale nigdy tak naprawdę nie mogę - cóż, to kolejna dobra okazja. Rozumiem trochę o zasięgu globalnym i globalnie dostępne metody z pewnością mogą być wygodne, ale czuję się trochę nieswojo z powodu ich nadużywania. W każdym razie wszystkie dotychczasowe odpowiedzi mówią mi, że nie powinienem odrzucać modułów z ręki; istnieją dobre powody, aby używać ich w odpowiednich okolicznościach.
Tom Juergens
12

Dopuszczalne jest użycie Module. Modulenie jest używany jako zamiennik Class. Modulesłuży swojemu celowi. Celem Modulejest użycie jako pojemnika

  • metody rozszerzania,
  • zmienne, które nie są specyficzne dla żadnego Class, lub
  • zmienne, które nie pasują poprawnie do żadnego Class.

Modulenie jest jak a, Classponieważ nie możesz

  • dziedziczyć po Module,
  • wdrożyć Interfacez Module,
  • ani nie tworzyć instancji pliku Module.

Do wszystkiego wewnątrz a Modulemożna uzyskać bezpośredni dostęp w ramach Modulezespołu bez odwoływania się do Modulejego nazwy. Domyślnie poziom dostępu dla a Moduleto Friend.

Chandra Malla
źródło
11

Zajęcia

  • klasy mogą być tworzone jako obiekty
  • Dane opisowe istnieją osobno dla każdego instancji obiektu.
  • klasy mogą implementować interfejsy .
  • Elementy członkowskie zdefiniowane w klasie są objęte zakresem określonego wystąpienia klasy i istnieją tylko przez cały okres istnienia obiektu .
  • Aby uzyskać dostęp do członków klasy spoza klasy, należy używać w pełni kwalifikowanych nazw w formacie Object.Member .

Moduły

  • Moduły nie mogą być tworzone jako obiekty , ponieważ istnieje tylko jedna kopia danych modułu standardowego, gdy jedna część programu zmienia zmienną publiczną w module standardowym, będzie ona widoczna dla całego programu.
  • Członkowie zadeklarowani w module są domyślnie dostępni publicznie .
  • Można uzyskać do niego dostęp za pomocą dowolnego kodu, który ma dostęp do modułu.
  • Oznacza to, że zmienne w standardowym module są w rzeczywistości zmiennymi globalnymi, ponieważ są widoczne z dowolnego miejsca w projekcie i istnieją przez cały okres istnienia programu.
Suji
źródło
6

Kiedy jedna z moich klas VB.NET ma wszystkich współdzielonych członków, konwertuję ją na Module z pasującą (lub w inny sposób odpowiednią) przestrzenią nazw lub sprawiam, że klasa nie jest dziedziczona ani konstruowana:

Public NotInheritable Class MyClass1

   Private Sub New()
      'Contains only shared members.
      'Private constructor means the class cannot be instantiated.
   End Sub

End Class
JRS
źródło
3
A oto składnia do przestrzeni nazw modułu: Imports <whatever>jeśli masz jakiekolwiek importu, Namespace MyCoolModule, Public Module MyCoolModule, <członkowie bez Shared >, End Module, End Namespace.
Rory O'Kane
0

Moduły nadają się do przechowywania wyliczeń i niektórych zmiennych globalnych, stałych i funkcji wspólnych. to bardzo dobra rzecz i często z niej korzystam. Zadeklarowane zmienne są widoczne w całym projekcie.

GGSoft
źródło
0

Jeśli tworzysz metody rozszerzające, musisz użyć modułu (zamiast klasy). W VB.NET nie znam innej opcji.

Będąc odpornym na moduły, spędziłem bezwartościowe kilka godzin próbując wymyślić, jak dodać jakiś standardowy kod, aby rozwiązać osadzone zespoły w jednym, tylko po to, aby dowiedzieć się, że Sub New()(Moduł) i Shared Sub New()(Klasa) są równoważne. (I nawet nie wiedzą, że nie było wywoływalnymSub New() w module!)

Więc po prostu rzucił EmbeddedAssembly.Loadi AddHandler AppDomain.CurrentDomain.AssemblyResolvelinie tam i Bob stał wuj.

Dodatek : nie sprawdziłem jeszcze tego w 100%, ale mam podejrzenie, które Sub New()działa w innej kolejności w module niż w klasie, po prostu przechodząc przez fakt, że musiałem przenieść niektóre deklaracje do metod wewnętrznych z zewnątrz, aby tego uniknąć błędy.

SteveCinq
źródło