Risposte:
Il più grande uso di classi parziali è di rendere la vita più facile per i generatori / progettisti di codice. Le classi parziali consentono al generatore di emettere semplicemente il codice che devono emettere e non devono gestire le modifiche dell'utente al file. Allo stesso modo, gli utenti sono liberi di annotare la classe con i nuovi membri disponendo di una seconda classe parziale. Ciò fornisce un quadro molto pulito per la separazione delle preoccupazioni.
Un modo migliore per vederlo è vedere come funzionavano i designer prima delle lezioni parziali. Il designer di WinForms avrebbe sputato tutto il codice all'interno di una regione con commenti fortemente formulati sulla non modifica del codice. Doveva inserire ogni sorta di euristica per trovare il codice generato per successive elaborazioni. Ora può semplicemente aprire il file designer.cs e avere un alto grado di sicurezza che contiene solo codice rilevante per il designer.
Un altro uso è quello di dividere l'implementazione di diverse interfacce, ad esempio:
partial class MyClass : IF1, IF2, IF3
{
// main implementation of MyClass
}
partial class MyClass
{
// implementation of IF1
}
partial class MyClass
{
// implementation of IF2
}
Implements
parola chiave per indicare un metodo appartiene a un'interfaccia)
A parte le altre risposte ...
Li ho trovati utili come trampolino di lancio nel refactoring delle classi divine. Se una classe ha più responsabilità (specialmente se si tratta di un file di codice molto grande), trovo utile aggiungere 1x classe di responsabilità parziale come primo passaggio per l'organizzazione e quindi il refactoring del codice.
Questo aiuta molto perché può aiutare a rendere il codice molto più leggibile senza effettivamente influenzare il comportamento di esecuzione. Può anche aiutare a identificare quando una responsabilità è facile da escludere o è strettamente aggrovigliata con altri aspetti.
Tuttavia - per essere chiari - questo è ancora un codice errato, alla fine dello sviluppo vuoi ancora una responsabilità per classe ( NON per classe parziale). È solo un trampolino di lancio :)
Solo dichiarazione del metodo parziale Anche il codice viene compilato solo con la dichiarazione del metodo e se l'implementazione del metodo non è presente il compilatore può rimuovere in modo sicuro quel pezzo di codice e non si verificherà alcun errore di tempo di compilazione.
Per verificare il punto 4. È sufficiente creare un progetto winform e includere questa riga dopo il costruttore Form1 e provare a compilare il codice
partial void Ontest(string s);
Ecco alcuni punti da considerare durante l'implementazione delle classi parziali: -
Un grande uso è la separazione del codice generato dal codice scritto a mano che appartiene alla stessa classe.
Ad esempio, poiché LINQ to SQL utilizza classi parziali, è possibile scrivere la propria implementazione di determinate funzionalità (come le relazioni Many-to-Many) e tali parti di codice personalizzato non verranno sovrascritte quando si rigenererà il codice.
Lo stesso vale per il codice WinForms. Tutto il codice generato da Designer si trova in un file che generalmente non tocchi. Il tuo codice scritto a mano va in un altro file. In questo modo, quando cambi qualcosa in Designer, le tue modifiche non vengono spazzate via.
È vero che la classe parziale viene utilizzata nella generazione automatica del codice, un uso può essere quello di mantenere un file di classe di grandi dimensioni che potrebbe avere migliaia di righe di codice. Non sai mai che la tua classe potrebbe finire con 10 mila righe e non vuoi creare una nuova classe con un nome diverso.
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.
Un altro possibile uso potrebbe essere che più di uno sviluppatore possa lavorare sulla stessa classe in quanto sono memorizzati in luoghi diversi. Le persone potrebbero ridere ma non sai mai che a volte può essere una manciata.
public partial class Product
{
//you are writing the business logic for fast moving product
}
public partial class Product
{
// Another developer writing some business logic...
}
Spero abbia senso!
Le classi parziali si estendono su più file.
Come puoi usare il modificatore parziale su una dichiarazione di classe C #?
Con le classi parziali, puoi separare fisicamente una classe in più file. Questo è spesso fatto dai generatori di codice.
Esempio
Con le normali classi C #, non è possibile dichiarare una classe in due file separati nello stesso progetto. Ma con il partial
modificatore, puoi.
Ciò è utile se un file viene comunemente modificato e l'altro è generato automaticamente o raramente modificato.
Ecco un esempio per chiarire:
class Program
{
static void Main()
{
A.A1();
A.A2();
}
}
Contenuto del file A1.cs: C #
using System;
partial class A
{
public static void A1()
{
Console.WriteLine("A1");
}
}
Contenuto del file A2.cs: C #
using System;
partial class A
{
public static void A2()
{
Console.WriteLine("A2");
}
}
Produzione:
A1
A2
Parziale è richiesto qui.
Se rimuovi il partial
modificatore, otterrai un errore contenente questo testo:
[Lo spazio dei nomi '
<global namespace>
' contiene già una definizione per 'A
'].
Mancia:
Per risolvere questo problema, puoi utilizzare la partial
parola chiave o modificare uno dei nomi delle classi.
In che modo il compilatore C # gestisce le classi parziali?
Se si disassembla il programma sopra (usando IL Disassembler), vedrai che i file A1.cs e A2.cs vengono eliminati. Scoprirai che è presente la classe A.
La classe A conterrà i metodi A1 e A2 nello stesso blocco di codice. Le due classi sono state unite in una.
Risultato compilato di A1.cs e A2.cs: C #
internal class A
{
// Methods
public static void A1()
{
Console.WriteLine("A1");
}
public static void A2()
{
Console.WriteLine("A2");
}
}
Sommario
mantieni tutto il più pulito possibile quando lavori con grandi classi o quando lavori in gruppo, puoi modificare senza ignorare (o sempre apportare modifiche)
Se hai una classe sufficientemente ampia che non si presta a un refactoring efficace, separarla in più file aiuta a mantenere le cose organizzate.
Ad esempio, se si dispone di un database per un sito contenente un forum di discussione e un sistema di prodotti e non si desidera creare due classi di provider diversi (NON la stessa cosa di una classe proxy, solo per essere chiari), è possibile creare una singola classe parziale in diversi file, come
MyProvider.cs - logica di base
MyProvider.Forum.cs - metodi specifici per il forum
MyProvider.Product.cs - metodi per i prodotti
È solo un altro modo per organizzare le cose.
Inoltre, come altri hanno già detto, si tratta dell'unico modo per aggiungere metodi a una classe generata senza correre il rischio che le aggiunte vengano distrutte alla successiva rigenerazione della classe. Questo è utile con codice generato dal modello (T4), ORM, ecc.
In alternativa alle direttive pre-compilatore.
Se usi le direttive pre-compilatore (vale a dire #IF DEBUG
), finisci con un codice dall'aspetto nodoso mescolato al tuo attuale codice di rilascio.
È possibile creare una classe parziale separata per contenere questo codice e racchiudere l'intera classe parziale in una direttiva oppure omettere tale file di codice dall'invio al compilatore (facendo effettivamente lo stesso).
I riferimenti di servizio sono un altro esempio in cui le classi parziali sono utili per separare il codice generato dal codice creato dall'utente.
È possibile "estendere" le classi di servizio senza sovrascriverle quando si aggiorna il riferimento del servizio.
Un altro uso che ho visto è
Estensione di una grande classe astratta per quanto riguarda la logica di accesso ai dati,
ho vari file con nomi 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..
}
Molte persone osservano che partial
dovrebbe essere usato solo per una classe che ha un file di codice generato o per le interfacce. Non sono d'accordo, ed ecco il perché.
Per un esempio, diamo un'occhiata alla classe System.Math di C # ... questa è la classe . Non tenterei di inserire più di 70 metodi nello stesso file a codice singolo. Sarebbe un incubo da mantenere.
Posizionare ogni metodo matematico in singoli file di classe parziali e tutti i file di codice in una cartella Math nel progetto sarebbe un'organizzazione molto più pulita.
Lo stesso potrebbe / sarebbe vero per molte altre classi che hanno una grande quantità di funzionalità diverse. Ad esempio, una classe per la gestione dell'API PrivateProfile potrebbe trarre vantaggio dalla suddivisione in un set pulito di file di classi parziali in una singola cartella di progetto.
Personalmente, ho anche diviso ciò che la maggior parte delle persone chiama classi "helper" o "utility" in singoli file parziali per ciascun metodo o gruppo funzionale di metodo. Ad esempio, in un progetto la classe helper di stringa ha quasi 50 metodi. Sarebbe un file di codice lungo e ingombrante anche usando le regioni. È significativamente più facile da mantenere utilizzando singoli file di classe parziale per ciascun metodo.
Starei solo attento usando le classi parziali e manterrei coerente tutto il layout del file di codice durante il progetto. Ad esempio, inserendo qualsiasi enumerazione pubblica di classe e membri di classe privati in un file Common.cs o con un nome simile nella cartella, anziché distribuirli sui file a meno che non siano specifici solo del file parziale in cui sono contenuti.
Tieni presente che quando dividi una classe in file separati perdi anche la possibilità di utilizzare la barra di divisione dell'editor di testo che ti consente di visualizzare contemporaneamente due diverse sezioni di un file corrente.
Le classi parziali consentono di aggiungere funzionalità a un programma adeguatamente progettato semplicemente aggiungendo file di origine. Ad esempio, è possibile progettare un programma di importazione di file in modo da poter aggiungere diversi tipi di file noti aggiungendo moduli che li gestiscono. Ad esempio, il convertitore del tipo di file principale potrebbe includere una piccola classe:
Classe pubblica parziale zzFileConverterRegistrar Registro eventi (ByVal mainConverter come zzFileConverter) Sottoregistratore Tutti (ByVal mainConverter as zzFileConverter) RaiseEvent Register (mainConverter) End Sub End Class
Ogni modulo che desidera registrare uno o più tipi di convertitore di file potrebbe includere qualcosa come:
Classe pubblica parziale zzFileConverterRegistrar Private Sub RegisterGif (ByVal mainConverter as zzFileConverter) Gestisce Me.Register mainConverter.RegisterConverter ("GIF", GifConverter.NewFactory)) End Sub End Class
Si noti che la classe principale del convertitore di file non è "esposta", ma espone solo una piccola classe di stub a cui i moduli aggiuntivi possono agganciarsi. Esiste un leggero rischio di conflitti di denominazione, ma se la routine di "registrazione" di ciascun modulo aggiuntivo viene denominata in base al tipo di file che gestisce, probabilmente non dovrebbero costituire un problema. Uno potrebbe attaccare un GUID nel nome della subroutine di registrazione se fosse preoccupato per tali cose.
Modifica / Addendum Per essere chiari, lo scopo è quello di fornire un mezzo attraverso il quale una varietà di classi separate possono far conoscere un programma principale o una classe. L'unica cosa che farà il convertitore di file principale con zzFileConverterRegistrar è crearne un'istanza e chiamare il metodo registerAll che genererà l'evento Register. Qualsiasi modulo che vuole agganciare quell'evento può eseguire un codice arbitrario in risposta ad esso (questa è l'intera idea) ma non c'è niente che un modulo possa fare estendendo in modo improprio la classe zzFileConverterRegistrar se non definire un metodo il cui nome corrisponde a quello di qualcos'altro . Sarebbe certamente possibile per un'estensione scritta in modo improprio rompere un'altra estensione scritta in modo improprio, ma la soluzione è che chiunque non desideri che l'estensione venga semplicemente scritta correttamente.
Uno, senza usare le classi parziali, potrebbe avere un po 'di codice da qualche parte all'interno della classe principale del convertitore di file, che assomiglia a:
RegisterConverter ("GIF", GifConvertor.NewFactory) RegisterConverter ("BMP", BmpConvertor.NewFactory) RegisterConverter ("JPEG", JpegConvertor.NewFactory)
ma aggiungere un altro modulo convertitore richiederebbe di entrare in quella parte del codice del convertitore e aggiungere il nuovo convertitore all'elenco. L'uso di metodi parziali non è più necessario: tutti i convertitori verranno inclusi automaticamente.
IModule
interfaccia?
IModule
, puoi usare un framework di plugin come MEF (solo uno dei tanti), ecc. Ecc.
Recentemente classi parziali hanno aiutato con il controllo del codice sorgente in cui più sviluppatori stavano aggiungendo a un file in cui venivano aggiunti nuovi metodi nella stessa parte del file (automatizzata da Resharper).
Queste spinte a git hanno causato conflitti di unione. Non ho trovato alcun modo per dire allo strumento di unione di prendere i nuovi metodi come blocco di codice completo.
Classi parziali a questo proposito consentono agli sviluppatori di attenersi a una versione del loro file e possiamo ricollegarli manualmente in seguito.
esempio -
Da MSDN :
1.In fase di compilazione, gli attributi delle definizioni di tipo parziale vengono uniti. Ad esempio, considerare le seguenti dichiarazioni:
[SerializableAttribute]
partial class Moon { }
[ObsoleteAttribute]
partial class Moon { }
Sono equivalenti alle seguenti dichiarazioni:
[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }
Di seguito vengono unite da tutte le definizioni di tipo parziale:
Commenti XML
interfacce
attributi di parametro di tipo generico
attributi di classe
membri
2. Un'altra cosa, le classi parziali nidificate possono anche essere parziali:
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
Ecco un elenco di alcuni dei vantaggi delle classi parziali.
È possibile separare il codice di progettazione dell'interfaccia utente e il codice della logica aziendale in modo che sia facile da leggere e comprendere. Ad esempio, stai sviluppando un'applicazione Web utilizzando Visual Studio e aggiungi un nuovo modulo Web, quindi ci sono due file di origine, "aspx.cs" e "aspx.designer.cs". Questi due file hanno la stessa classe con la parola chiave parziale. La classe ".aspx.cs" ha il codice della logica aziendale mentre "aspx.designer.cs" ha la definizione del controllo dell'interfaccia utente.
Quando si lavora con l'origine generata automaticamente, è possibile aggiungere il codice alla classe senza dover ricreare il file di origine. Ad esempio, stai lavorando con LINQ to SQL e crei un file DBML. Ora quando trascini e rilasci una tabella crea una classe parziale in designer.cs e tutte le colonne della tabella hanno proprietà nella classe. Sono necessarie più colonne in questa tabella per eseguire il bind sulla griglia dell'interfaccia utente ma non si desidera aggiungere una nuova colonna alla tabella del database in modo da poter creare un file di origine separato per questa classe che abbia una nuova proprietà per quella colonna e essere una classe parziale. Ciò influisce sul mapping tra la tabella del database e l'entità DBML, ma è possibile ottenere facilmente un campo aggiuntivo. Significa che puoi scrivere il codice da solo senza fare confusione con il codice generato dal sistema.
Più di uno sviluppatore può scrivere contemporaneamente il codice per la classe.
È possibile gestire meglio l'applicazione compattando classi di grandi dimensioni. Supponiamo di avere una classe con più interfacce in modo da poter creare più file di origine in base agli strumenti dell'interfaccia. È facile capire e mantenere un'interfaccia implementata su cui il file sorgente ha una classe parziale.
Ogni volta che ho una classe che contiene una classe nidificata di qualsiasi dimensione / complessità significativa, segnare la classe come partial
e inserisco la classe nidificata in un file separato. Nomino il file contenente la classe nidificata usando la regola: [nome classe]. [Nome classe nidificata] .cs.
Il seguente blog MSDN spiega come utilizzare le classi parziali con le classi nidificate per la manutenibilità: http://blogs.msdn.com/b/marcelolr/archive/2009/04/13/using-partial-classes-with-nested-classes-for- maintainability.aspx
So che questa domanda è davvero vecchia, ma vorrei solo aggiungere il mio giudizio sulle lezioni parziali.
Uno dei motivi per cui utilizzo personalmente le classi parziali è quando creo i collegamenti per un programma, in particolare le macchine a stati.
Ad esempio, OpenGL è una macchina a stati, ci sono un sacco di metodi che possono essere tutti cambiati a livello globale, tuttavia, nella mia esperienza, legando qualcosa di simile a OpenGL in cui ci sono così tanti metodi, la classe può facilmente superare 10k LOC.
Le lezioni parziali lo analizzeranno per me e mi aiuteranno a trovare rapidamente i metodi.
Le classi parziali vengono introdotte principalmente per aiutare i generatori di codice, quindi noi (utenti) non finiamo per perdere tutto il nostro lavoro / modifiche alle classi generate come la classe .designer.cs di ASP.NET ogni volta che ci rigeneriamo, quasi tutti i nuovi strumenti che generano codice LINQ, EntityFrameworks, ASP.NET utilizzano classi parziali per il codice generato, quindi possiamo aggiungere o alterare in sicurezza la logica di questi codici generati sfruttando le classi e i metodi parziali, ma prestando molta attenzione prima di aggiungere elementi al codice generato usando le classi parziali è più semplice se rompiamo la build, ma peggio se introduciamo errori di runtime. Per ulteriori dettagli, consultare questo http://www.4guysfromrolla.com/articles/071509-1.aspx
Prendo atto di due usi che non sono riuscito a trovare esplicitamente nelle risposte.
Alcuni sviluppatori usano i commenti per separare diverse "parti" della loro classe. Ad esempio, un team potrebbe utilizzare la seguente convenzione:
public class MyClass{
//Member variables
//Constructors
//Properties
//Methods
}
Con le classi parziali, possiamo fare un passo ulteriore e dividere le sezioni in file separati. Come convenzione, una squadra potrebbe aggiungere un suffisso a ciascun file con la sezione corrispondente ad esso. Quindi in quanto sopra avremmo qualcosa di simile: MyClassMembers.cs, MyClassConstructors.cs, MyClassProperties.cs, MyClassMethods.cs.
Come è stato accennato ad altre risposte, se vale la pena dividere la classe o meno dipende probabilmente da quanto è grande la classe in questo caso. Se è piccolo, probabilmente è più facile avere tutto in una master class. Ma se una di quelle sezioni diventa troppo grande, il suo contenuto può essere spostato in una classe parziale separata, al fine di mantenere la classe principale in ordine. Una convenzione in tal caso potrebbe essere quella di lasciare un commento dicendo qualcosa come "Vedi classe parziale" dopo l'intestazione della sezione, ad esempio:
//Methods - See partial class
Questo è probabilmente un evento raro, ma potrebbe esserci una collisione dello spazio dei nomi tra due funzioni delle librerie che si desidera utilizzare. In una singola classe, potresti utilizzare al massimo una clausola using per una di queste. Per l'altro avresti bisogno di un nome completo o di un alias. Con le classi parziali, poiché ogni spazio dei nomi e l'utilizzo dell'elenco delle istruzioni è diverso, si potrebbero separare i due insiemi di funzioni in due file separati.
using Library1 = The.Namespace.You.Need
oglobal::Root.Of.Namespace