Odpowiedzi:
Największym zastosowaniem klas częściowych jest ułatwienie życia generatorom / projektantom kodów. Klasy częściowe pozwalają generatorowi po prostu wyemitować kod, który muszą wyemitować i nie muszą zajmować się edycją pliku przez użytkownika. Użytkownicy mogą również dodawać adnotacje do klasy z nowymi członkami, mając drugą klasę częściową. Zapewnia to bardzo czyste ramy dla rozdzielenia problemów.
Lepszym sposobem na to jest sprawdzenie, jak projektanci funkcjonowali przed częściowymi zajęciami. Projektant WinForm wyplułby cały kod w regionie z silnie sformułowanymi komentarzami na temat nie modyfikowania kodu. Musiał wstawić wszelkiego rodzaju heurystykę, aby znaleźć wygenerowany kod do późniejszego przetworzenia. Teraz może po prostu otworzyć plik designer.cs i mieć wysoki stopień pewności, że zawiera tylko kod odpowiedni dla projektanta.
Innym zastosowaniem jest podzielenie implementacji różnych interfejsów, np .:
partial class MyClass : IF1, IF2, IF3
{
// main implementation of MyClass
}
partial class MyClass
{
// implementation of IF1
}
partial class MyClass
{
// implementation of IF2
}
Implements
słowa kluczowego do oznaczenia metody należy do interfejsu)
Oprócz innych odpowiedzi ...
Uważam, że są one pomocne jako odskocznia w refaktoryzacji klas bożych. Jeśli klasa ma wiele obowiązków (szczególnie jeśli jest to bardzo duży plik kodu), uważam za korzystne dodanie 1x częściowej klasy na odpowiedzialność jako pierwszego przejścia do organizacji, a następnie refaktoryzacji kodu.
Pomaga to znacznie, ponieważ może pomóc w zwiększeniu czytelności kodu bez faktycznego wpływu na zachowanie. Może również pomóc w określeniu, kiedy odpowiedzialność można łatwo zrefaktoryzować lub jest ona ściśle związana z innymi aspektami.
Jednak - żeby być jasnym - jest to nadal zły kod, na końcu rozwoju nadal potrzebujesz jednej odpowiedzialności na klasę ( NIE na klasę częściową). To tylko odskocznia :)
Tylko częściowa deklaracja metody Nawet kod zostanie skompilowany tylko z deklaracją metody, a jeśli implementacja metody nie jest obecna, kompilator może bezpiecznie usunąć ten fragment kodu i nie wystąpi błąd czasu kompilacji.
Aby zweryfikować punkt 4. Po prostu utwórz projekt winform i dołącz ten wiersz za konstruktorem Form1 i spróbuj skompilować kod
partial void Ontest(string s);
Oto kilka punktów do rozważenia przy wdrażaniu klas częściowych:
Jednym z wielkich zastosowań jest oddzielenie generowanego kodu od odręcznego kodu należącego do tej samej klasy.
Na przykład, ponieważ LINQ do SQL używa klas częściowych, możesz napisać własną implementację niektórych funkcji (takich jak relacje wiele do wielu), a te fragmenty niestandardowego kodu nie zostaną zastąpione podczas ponownego generowania kodu.
To samo dotyczy kodu WinForms. Cały kod wygenerowany przez Projektanta znajduje się w jednym pliku, którego zazwyczaj nie dotykasz. Twój ręcznie napisany kod trafia do innego pliku. W ten sposób, gdy zmienisz coś w Projektancie, twoje zmiany nie zostaną zdmuchnięte.
Prawdą jest, że Partial Class jest używana do automatycznego generowania kodu, jednym z zastosowań może być utrzymanie dużego pliku klasy, który może zawierać tysiące wierszy kodu. Nigdy nie wiesz, że Twoja klasa może skończyć z 10 tysiącami linii i nie chcesz tworzyć nowej klasy o innej nazwie.
public partial class Product
{
// 50 business logic embedded in methods and properties..
}
public partial class Product
{
// another 50 business logic embedded in methods and properties..
}
//finally compile with product.class file.
Innym możliwym zastosowaniem może być to, że więcej niż jeden programista może pracować na tej samej klasie, ponieważ są one przechowywane w różnych miejscach. Ludzie mogą się śmiać, ale nigdy nie wiadomo, że czasem może być garstka.
public partial class Product
{
//you are writing the business logic for fast moving product
}
public partial class Product
{
// Another developer writing some business logic...
}
Mam nadzieję, że to ma sens!
Klasy częściowe obejmują wiele plików.
Jak można użyć częściowego modyfikatora deklaracji klasy C #?
Dzięki klasom częściowym możesz fizycznie podzielić klasę na wiele plików. Jest to często wykonywane przez generatory kodu.
Przykład
W przypadku normalnych klas C # nie można zadeklarować klasy w dwóch osobnych plikach w tym samym projekcie. Ale z partial
modyfikatorem możesz.
Jest to przydatne, jeśli jeden plik jest często edytowany, a drugi jest generowany komputerowo lub rzadko edytowany.
Oto przykład, aby wyjaśnić:
class Program
{
static void Main()
{
A.A1();
A.A2();
}
}
Zawartość pliku A1.cs: C #
using System;
partial class A
{
public static void A1()
{
Console.WriteLine("A1");
}
}
Zawartość pliku A2.cs: C #
using System;
partial class A
{
public static void A2()
{
Console.WriteLine("A2");
}
}
Wynik:
A1
A2
Częściowe jest tutaj wymagane.
Jeśli usuniesz partial
modyfikator, pojawi się błąd zawierający ten tekst:
[Przestrzeń nazw ”
<global namespace>
zawiera już definicjęA
„].
Wskazówka:
Aby to naprawić, możesz użyć partial
słowa kluczowego lub zmienić jedną z nazw klas.
Jak kompilator C # radzi sobie z klasami częściowymi?
Jeśli zdemontujesz powyższy program (używając IL Disassembler), zobaczysz, że pliki A1.cs i A2.cs zostaną wyeliminowane. Przekonasz się, że klasa A jest obecna.
Klasa A będzie zawierać metody A1 i A2 w tym samym bloku kodu. Dwie klasy zostały połączone w jedną.
Skompilowany wynik A1.cs i A2.cs: C #
internal class A
{
// Methods
public static void A1()
{
Console.WriteLine("A1");
}
public static void A2()
{
Console.WriteLine("A2");
}
}
Podsumowanie
utrzymuj wszystko tak czyste, jak to możliwe, podczas pracy z dużymi klasami lub podczas pracy w zespole, możesz edytować bez zastępowania (lub zawsze zatwierdzania zmian)
Głównym zastosowaniem klas częściowych jest wygenerowany kod. Jeśli spojrzysz na sieć WPF (Windows Presentation Foundation), zdefiniujesz interfejs użytkownika za pomocą znaczników (XML). Ten znacznik jest skompilowany na częściowe klasy. Wypełniacie kod własnymi częściowymi klasami.
Jeśli masz wystarczająco dużą klasę, która nie nadaje się do skutecznego refaktoryzacji, podzielenie jej na wiele plików pomaga utrzymać porządek.
Na przykład, jeśli masz bazę danych witryny zawierającą forum dyskusyjne i system produktów, a nie chcesz tworzyć dwóch różnych klas dostawców (NIE to samo co klasa proxy, żeby być czystym), możesz: utwórz pojedynczą klasę częściową w różnych plikach, takich jak
MyProvider.cs - podstawowa logika
MyProvider.Forum.cs - metody odnoszące się konkretnie do forum
MyProvider.Product.cs - metody dla produktów
To tylko kolejny sposób na uporządkowanie.
Ponadto, jak powiedzieli inni, jest to jedyny sposób na dodanie metod do wygenerowanej klasy bez ryzyka zniszczenia twoich dodatków przy następnym generowaniu klasy. Jest to przydatne w przypadku kodu generowanego na podstawie szablonu (T4), ORM itp.
Jako alternatywa dla dyrektyw prekompilatora.
Jeśli użyjesz dyrektyw prekompilatora (mianowicie #IF DEBUG
), to skończysz z jakimś srogo wyglądającym kodem zmieszanym z twoim faktycznym kodem Release.
Możesz utworzyć oddzielną klasę częściową, aby zawierała ten kod i albo zawinąć całą klasę częściową w dyrektywę, albo pominąć przesłanie tego pliku kodu do kompilatora (robiąc to samo).
Odwołania do usług to kolejny przykład, w którym klasy częściowe są przydatne do oddzielenia generowanego kodu od kodu utworzonego przez użytkownika.
Możesz „rozszerzyć” klasy usług bez konieczności ich zastępowania podczas aktualizacji odwołania do usługi.
Innym zastosowaniem, które widziałem, jest
Rozszerzenie dużej klasy abstrakcyjnej dotyczącej logiki dostępu do danych,
Mam różne pliki o nazwach Post.cs, Comment.cs, Pages.cs ...
in Post.cs
public partial class XMLDAO :BigAbstractClass
{
// CRUD methods of post..
}
in Comment.cs
public partial class XMLDAO :BigAbstractClass
{
// CRUD methods of comment..
}
in Pages.cs
public partial class XMLDAO :BigAbstractClass
{
// CRUD methods of Pages..
}
Większość ludzi zauważa, że partial
należy tego używać tylko w przypadku klasy, która ma wygenerowany plik kodu lub interfejsów. Nie zgadzam się, a oto dlaczego.
Na przykład spójrzmy na klasę C # System.Math ... to klasa . Nie próbowałbym wpychać ponad 70 metod do tego samego pojedynczego pliku kodu. Utrzymanie tego byłoby koszmarem.
Umieszczenie każdej metody matematycznej w oddzielnych plikach klas częściowych i wszystkich plików kodu w folderze Math w projekcie byłoby znacznie czystszą organizacją.
To samo mogłoby / dotyczyłoby wielu innych klas, które mają dużą różnorodność funkcji. Na przykład klasa do zarządzania API PrivateProfile mogłaby skorzystać z podziału na czysty zestaw plików klas częściowych w jednym folderze projektu.
Osobiście podzieliłem również to, co większość ludzi nazywa klasami „pomocników” lub „narzędzi użytkowych” na pojedyncze pliki częściowe dla każdej metody lub grupy funkcjonalnej metody. Na przykład w jednym projekcie klasa pomocnicza łańcucha ma prawie 50 metod. Byłby to długi, nieporęczny plik kodu, nawet przy użyciu regionów. Znacznie łatwiej jest utrzymać używanie poszczególnych plików klas częściowych dla każdej metody.
Byłbym ostrożny przy stosowaniu klas częściowych i utrzymywałby przy tym cały układ pliku kodu w całym projekcie. Takie jak umieszczanie dowolnych publicznych wyliczeń i prywatnych członków klasy w pliku Common.cs lub pliku o podobnej nazwie w folderze, zamiast rozkładania ich na pliki, chyba że są one specyficzne tylko dla pliku częściowego, w którym się znajdują.
Pamiętaj, że dzieląc klasę na osobne pliki, tracisz także możliwość korzystania z paska podziału edytora tekstów, który umożliwia jednoczesne wyświetlanie dwóch różnych sekcji bieżącego pliku.
Klasy częściowe umożliwiają dodanie funkcjonalności do odpowiednio zaprojektowanego programu poprzez dodanie plików źródłowych. Na przykład można zaprojektować program do importowania plików, aby można było dodawać różne typy znanych plików, dodając moduły, które je obsługują. Na przykład główny konwerter typów plików może zawierać małą klasę:
Częściowa klasa publiczna zzFileConverterRegistrar Rejestr zdarzeń (ByVal mainConverter jako zzFileConverter) Sub registerAll (ByVal mainConverter as zzFileConverter) RaiseEvent Register (mainConverter) Napis końcowy Klasa końcowa
Każdy moduł, który chce zarejestrować jeden lub więcej typów konwertera plików, może zawierać coś takiego:
Częściowa klasa publiczna zzFileConverterRegistrar Private Sub RegisterGif (ByVal mainConverter as zzFileConverter) Obsługuje rejestrację mainConverter.RegisterConverter („GIF”, GifConverter.NewFactory)) Napis końcowy Klasa końcowa
Zauważ, że główna klasa konwertera plików nie jest „odsłonięta” - po prostu odsłania małą klasę kodu pośredniczącego, do której moduły dodatkowe mogą się zaczepić. Istnieje niewielkie ryzyko konfliktu nazw, ale jeśli procedura „rejestru” każdego modułu dodatkowego zostanie nazwana zgodnie z typem pliku, z którym ma do czynienia, prawdopodobnie nie powinien stanowić problemu. Można by umieścić identyfikator GUID w nazwie podprogramu rejestracyjnego, jeśli martwiłby się takimi rzeczami.
Edytuj / uzupełnienie Żeby było jasne, celem tego jest zapewnienie środków, dzięki którym różne osobne klasy mogą powiadomić o nich główny program lub klasę. Jedyną rzeczą, jaką główny konwerter plików zrobi z zFileConverterRegistrar, jest utworzenie jednej jego instancji i wywołanie metody registerAll, która wywoła zdarzenie Register. Każdy moduł, który chce przechwycić to zdarzenie, może wykonać dowolny kod w odpowiedzi (to cały pomysł), ale nie ma nic, co mógłby zrobić moduł, niewłaściwie rozszerzając klasę zzFileConverterRegistrar poza zdefiniowaniem metody, której nazwa odpowiada nazwie innego . Z pewnością byłoby możliwe, aby jedno niepoprawnie napisane rozszerzenie złamało inne niepoprawnie napisane rozszerzenie, ale rozwiązaniem tego jest dla każdego, kto nie chce, aby jego rozszerzenie zostało po prostu napisane poprawnie.
Można bez użycia klas częściowych mieć gdzieś wewnątrz głównej klasy konwertera plików trochę kodu, który wyglądałby tak:
RegisterConverter („GIF”, GifConvertor.NewFactory) RegisterConverter („BMP”, BmpConvertor.NewFactory) RegisterConverter („JPEG”, JpegConvertor.NewFactory)
ale dodanie innego modułu konwertera wymagałoby przejścia do tej części kodu konwertera i dodania nowego konwertera do listy. Przy użyciu metod częściowych, które nie są już konieczne - wszystkie konwertery zostaną uwzględnione automatycznie.
IModule
interfejs?
IModule
, możesz użyć frameworka takiego jak MEF (tylko jeden z wielu) itp.
Klasy częściowe pomogły ostatnio w kontroli źródła, w której wielu programistów dodawało do jednego pliku, w którym nowe metody były dodawane do tej samej części pliku (zautomatyzowane przez Resharper).
Te naciski na git spowodowały konflikty scalania. Nie znalazłem sposobu, aby powiedzieć narzędziu do scalania, aby przyjęło nowe metody jako kompletny blok kodu.
Częściowe klasy pod tym względem pozwalają programistom trzymać się wersji swojego pliku, a my możemy je później scalić ręcznie.
przykład -
Z MSDN :
1. W czasie kompilacji atrybuty definicji typu częściowego są scalane. Weźmy na przykład następujące deklaracje:
[SerializableAttribute]
partial class Moon { }
[ObsoleteAttribute]
partial class Moon { }
Odpowiadają one następującym deklaracjom:
[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }
Poniższe elementy zostały scalone ze wszystkich definicji typu częściowego:
Komentarze XML
interfejsy
atrybuty parametrów typu ogólnego
atrybuty klasy
członkowie
2. Inną rzeczą, zagnieżdżone klasy częściowe mogą być również częściowe:
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
Oto lista niektórych zalet klas częściowych.
Możesz oddzielić kod projektu interfejsu użytkownika od kodu logiki biznesowej, aby był łatwy do odczytania i zrozumienia. Na przykład tworzysz aplikację internetową za pomocą programu Visual Studio i dodajesz nowy formularz internetowy, a następnie są dwa pliki źródłowe: „aspx.cs” i „aspx.designer.cs”. Te dwa pliki mają tę samą klasę ze słowem kluczowym częściowym. Klasa „.aspx.cs” ma kod logiki biznesowej, natomiast „aspx.designer.cs” ma definicję kontroli interfejsu użytkownika.
Podczas pracy z automatycznie generowanym źródłem kod można dodać do klasy bez konieczności ponownego tworzenia pliku źródłowego. Na przykład pracujesz z LINQ to SQL i tworzysz plik DBML. Teraz, kiedy przeciągasz i upuszczasz tabelę, tworzy ona klasę częściową w designer.cs, a wszystkie kolumny tabeli mają właściwości w klasie. Potrzebujesz więcej kolumn w tej tabeli, aby powiązać się z siatką interfejsu użytkownika, ale nie chcesz dodawać nowej kolumny do tabeli bazy danych, abyś mógł utworzyć osobny plik źródłowy dla tej klasy, który ma nową właściwość dla tej kolumny i będzie być klasą częściową. Wpływa to na mapowanie między tabelą bazy danych a jednostką DBML, ale można łatwo uzyskać dodatkowe pole. Oznacza to, że możesz napisać kod samodzielnie, bez bałagania się kodu generowanego przez system.
Więcej niż jeden programista może jednocześnie napisać kod dla klasy.
Możesz lepiej utrzymać swoją aplikację, kompaktując duże klasy. Załóżmy, że masz klasę z wieloma interfejsami, dzięki czemu możesz tworzyć wiele plików źródłowych w zależności od implementacji interfejsu. Łatwo jest zrozumieć i utrzymać interfejs zaimplementowany, w którym plik źródłowy ma klasę częściową.
Ilekroć mam klasę, która zawiera zagnieżdżoną klasę o dowolnym znaczącym rozmiarze / złożoności, zaznaczam klasę jako partial
i umieszczam zagnieżdżoną klasę w osobnym pliku. Nazwa pliku zawierającego klasę zagnieżdżoną nazywam zgodnie z regułą: [nazwa klasy]. [Nazwa klasy zagnieżdżonej] .cs.
Poniższy blog MSDN wyjaśnia, jak używać klas częściowych z klasami zagnieżdżonymi w celu utrzymania: http://blogs.msdn.com/b/marcelolr/archive/2009/04/13/using-partial-classes-with-nested-classes-for- Maintenanceability.aspx
Wiem, że to pytanie jest naprawdę stare, ale chciałbym dodać moje zdanie na temat częściowych zajęć.
Jednym z powodów, dla których osobiście używam klas częściowych, jest tworzenie powiązań dla programu, zwłaszcza maszyn stanu.
Na przykład OpenGL jest maszyną stanu, istnieje mnóstwo metod, które można zmienić globalnie, jednak z mojego doświadczenia wiąże coś podobnego do OpenGL, gdzie jest tak wiele metod, klasa może łatwo przekroczyć 10 000 LOC.
Zajęcia częściowe rozłożą to na mnie i pomogą mi szybko znaleźć metody.
Klasy częściowe zostały wprowadzone przede wszystkim w celu pomocy generatorom kodów, więc my (użytkownicy) nie tracimy całej naszej pracy / zmian w generowanych klasach, takich jak klasa .designer.cs ASP.NET przy każdej regeneracji, prawie wszystkie nowe narzędzia, które generują kod LINQ, EntityFrameworks, ASP.NET używają klas częściowych do generowania kodu, dzięki czemu możemy bezpiecznie dodawać lub zmieniać logikę tych wygenerowanych kodów, korzystając z klas i metod Partial, ale zachowaj ostrożność, zanim dodasz elementy do generowanego kodu za pomocą klas Partial łatwiej jest, jeśli zepsujemy kompilację, a najgorsze, jeśli wprowadzimy błędy czasu wykonywania. Aby uzyskać więcej informacji, sprawdź ten http://www.4guysfromrolla.com/articles/071509-1.aspx
Zwracam uwagę na dwa zastosowania, których nie znalazłem wyraźnie w odpowiedziach.
Niektórzy programiści używają komentarzy do oddzielania różnych „części” swojej klasy. Na przykład zespół może zastosować następującą konwencję:
public class MyClass{
//Member variables
//Constructors
//Properties
//Methods
}
Dzięki klasom częściowym możemy pójść o krok dalej i podzielić sekcje na osobne pliki. Zgodnie z konwencją zespół może sufikować każdy plik odpowiednią sekcją. W powyższym przypadku mielibyśmy coś takiego: MyClassMembers.cs, MyClassConstructors.cs, MyClassProperties.cs, MyClassMethods.cs.
Jak wspomniano w innych odpowiedziach, to, czy warto podzielić klasę, prawdopodobnie zależy od tego, jak duża jest klasa w tym przypadku. Jeśli jest mały, prawdopodobnie łatwiej jest mieć wszystko w jednej klasie mistrzowskiej. Ale jeśli którakolwiek z tych sekcji stanie się zbyt duża, jej zawartość można przenieść do oddzielnej klasy częściowej, aby utrzymać klasę master w porządku. Konwencją w takim przypadku może być pozostawienie komentarza po powiedzeniu „Patrz częściowa klasa” po nagłówku sekcji, np .:
//Methods - See partial class
Jest to prawdopodobnie rzadkie zjawisko, ale może wystąpić kolizja przestrzeni nazw między dwiema funkcjami bibliotek, których chcesz użyć. W jednej klasie możesz co najwyżej użyć klauzuli using dla jednej z nich. Po drugie potrzebujesz w pełni kwalifikowanej nazwy lub aliasu. W przypadku klas częściowych, ponieważ każda lista przestrzeni nazw i instrukcji jest inna, można podzielić dwa zestawy funkcji na dwa osobne pliki.
using Library1 = The.Namespace.You.Need
lubglobal::Root.Of.Namespace