Domanda

Esistono buoni usi delle classi parziali al di fuori degli scenari di codice generato da webform / winform? O questa funzione è sostanzialmente di supporto?

È stato utile?

Soluzione

È in parte a supporto di scenari (WebForms, WinForms, LINQ-to-SQL, ecc.) che mescolano il codice generato con il codice del programmatore.

Ci sono più motivi per usarlo. Ad esempio, se si dispone di grandi classi in file di grandi dimensioni e ingombranti, ma le classi hanno gruppi di metodi logicamente correlati, le classi parziali possono essere un'opzione per rendere le dimensioni dei file più gestibili.

Altri suggerimenti

La generazione del codice è stata la forza trainante delle classi parziali. La necessità deriva dall'avere una classe generata da codice che è in continua evoluzione, ma consente agli sviluppatori di fornire codice personalizzato come parte della classe che non verrà sovrascritto ogni volta che vengono apportate modifiche che costringono la classe a essere rigenerata.

Prendi WinForms o Typed-DataSet per esempio (o qualsiasi designer per quella materia). Ogni volta che apporti una modifica al designer, serializza il codice corrispondente in un file. Diciamo che è necessario fornire alcuni metodi aggiuntivi di cui il generatore non sa nulla. Se lo aggiungessi al file generato, le modifiche andrebbero perse alla successiva generazione.

Un progetto a cui sto attualmente lavorando utilizza la generazione di codice per tutte le DAL, BLL e le entità aziendali. Tuttavia, il generatore ci fornisce solo il 75% delle informazioni. La parte rimanente deve essere codificata a mano (logica aziendale personalizzata per esempio). Posso presumere che ogni classe BLL abbia un metodo SelectAll, quindi è facile da generare. Tuttavia, il mio cliente BLL deve anche disporre di un metodo SelectAllByLocation. Non posso inserirlo nel mio generatore perché non è generico per tutte le classi BLL. Pertanto, generi tutte le mie classi come classi parziali e quindi in un file separato definisco i miei metodi personalizzati. Ora in fondo alla strada quando la mia struttura cambia, o ho bisogno di rigenerare il mio BLL per qualche motivo, il mio codice personalizzato non verrà cancellato.

Uso le classi parziali come mezzo per separare i diversi elementi secondari dei controlli personalizzati che scrivo. Inoltre, se utilizzato con il software di creazione di entità, consente a prodotti come LLBLGen di creare versioni generate di classi, nonché una versione personalizzata, modificata dall'utente, che non verrà sostituita se le entità devono essere rigenerate.

Uso spesso classi parziali per assegnare a ciascuna classe nidificata il proprio file. Ci sono state alcune architetture su cui ho lavorato in cui la maggior parte dell'implementazione era richiesta solo da una classe e quindi abbiamo annidato quelle classi in quella classe. Era logico mantenere i file più facili da gestire utilizzando l'abilità di classe parziale e suddividendo ciascuno nel proprio file.

Li abbiamo anche usati per raggruppare le sostituzioni di titoli o nascondere una serie di proprietà di titoli. Cose del genere. È un modo pratico di mescolare in un cambio di borsa (basta copiare il file e cambiare il nome della classe parziale nella classe target - purché anche la classe target sia resa parziale, ovviamente).

Un altro possibile utilizzo per le classi parziali sarebbe quello di sfruttare i metodi parziali per far scomparire selettivamente i metodi usando la compilazione condizionale - questo sarebbe ottimo per il codice diagnostico in modalità debug o scenari di test di unità specializzati.

Puoi dichiarare un tipo di metodo parziale simile a un metodo astratto, quindi nell'altra classe parziale, quando digiti la parola chiave " parziale " puoi sfruttare Intellisense per creare l'implementazione di quel metodo.

Se si circonda una parte con istruzioni di compilazione condizionale, è possibile tagliare facilmente solo il codice di debug o il test. Nell'esempio seguente, in modalità DEBUG, viene chiamato il metodo LogSomethingDebugOnly, ma nella build di rilascio è come se il metodo non esistesse affatto, un buon modo per mantenere il codice diagnostico lontano dal codice di produzione senza un mucchio di ramificazioni o più blocchi di compilazione condizionale.

// Main Part
public partial class Class1
{
    private partial void LogSomethingDebugOnly();

    public void SomeMethod()
    {
        LogSomethingDebugOnly();
        // do the real work
    }
}

// Debug Part - probably in a different file
public partial class Class1
{

    #if DEBUG

    private partial void LogSomethingDebugOnly()
    {
        // Do the logging or diagnostic work
    }

    #endif
}

LINQ to SQL fa buon uso delle classi parziali per estendere il codice generato dal progettista. Penso che in genere troverai questo modello di classi parziali utilizzato dal codice creato dal designer.

Trovo che le lezioni parziali siano estremamente utili. Di solito sono utilizzati per estendere le classi autogenerate. Li ho usati in un progetto con test di unità pesanti. Le mie classi UT avevano dipendenze complesse e non era molto pratico separare il codice tra più classi. Naturalmente è meglio usare l'ereditarietà \ composizione, ma in alcuni casi le classi parziali possono essere di aiuto.

Come accennato in precedenza, anche io penso che questo sia un odore di codice.

Se una classe è così grande che deve essere suddivisa in più file, significa che sta infrangendo il principio della singola responsabilità e sta facendo troppe cose. La grande classe potrebbe essere suddivisa in classi più piccole che cooperano insieme.

Se devi organizzare classi o regioni parziali per organizzare il codice, considera se dovrebbero essere nelle loro classi. Aumenta la leggibilità e otterrai un maggiore riutilizzo del codice.

forse è troppo tardi ma per favore fammi aggiungere anche i miei 2 centesimi:

*. Quando si lavora su progetti di grandi dimensioni, la diffusione di una classe su file separati consente a più programmatori di lavorarci simultaneamente.

* .Puoi scrivere facilmente il tuo codice (per funzionalità estese) per una classe generata VS.NET. Ciò ti consentirà di scrivere il codice di cui hai bisogno senza fare confusione con il codice generato dal sistema

Dove sono, abbiamo un programma che gestisce i file in arrivo dai client. È impostato in modo tale che il codice di ciascun client si trovi nel proprio progetto di libreria di classi, che sappia gestire qualunque formato il client scelga di utilizzare.

Il codice principale usa le librerie definendo un'interfaccia abbastanza estesa che una classe nella libreria deve implementare (probabilmente dovrebbero essere alcune interfacce distinte, ma è troppo tardi per cambiarla ora). A volte ciò comporta molto più codice nella stessa classe di quanto normalmente pensiamo prudente. Le lezioni parziali ci permettono di spezzarle un po '.

Su UserControls che sono relativamente complicati, inserisco l'evento che gestisce le cose in un file e il disegno e le proprietà in un altro file. Le classi parziali funzionano alla grande per questo, di solito queste parti della classe sono relativamente indipendenti ed è bello poter modificare la pittura e la gestione degli eventi fianco a fianco.

Ho lavorato su un progetto un paio di anni fa in cui avevamo una classe DataSet tipizzata che conteneva una tonnellata di codice: metodi nei DataTable, metodi nei TableAdapters, dichiarazioni delle istanze di TableAdapter, lo chiami. Era un enorme punto centrale del progetto su cui tutti dovevano lavorare spesso e c'erano molte contese sul controllo del codice sorgente sul file di codice di classe parziale.

Quindi ho diviso il file di codice in fix o sei file di classe parziali, raggruppati per funzione, in modo che potessimo lavorare su pezzi più piccoli e non dover bloccare l'intero file ogni volta che dovevamo cambiare qualcosa.

(Naturalmente, avremmo anche potuto risolvere il problema non utilizzando un sistema di controllo del codice sorgente che blocca esclusivamente, ma questo è un altro problema.)

In generale, lo considero un odore di codice.

Se la tua classe è così complicata, probabilmente può essere suddivisa in componenti riutilizzabili più piccoli.

Oppure significa che non esiste una gerarchia ereditaria in cui dovrebbe essercene una.

Per gli scenari di generazione del codice va bene, ma penso che la generazione del codice sia un altro odore di codice.

Sono in ritardo nel gioco ... ma solo i miei 2 centesimi ...

Un uso potrebbe essere il refactoring di una classe god esistente in una base di codice legacy esistente in più classi parziali. Potrebbe migliorare la rilevabilità del codice - se viene seguita un'adeguata convenzione di denominazione per i nomi dei file contenenti le classi parziali. Ciò potrebbe anche ridurre il repository del codice sorgente: risolvere e unire in misura.

Idealmente, una classe divina dovrebbe essere suddivisa in più classi piccole - ognuna con una singola responsabilità. A volte è dirompente eseguire rifatturazioni medio-grandi. In tali casi, le lezioni parziali potrebbero fornire un sollievo temporaneo.

Correzione, come ha sottolineato Matt, entrambi i lati del parziale devono essere nello stesso assieme. mio male.

Lo uso in un livello di accesso ai dati. Le classi generate come il mapper e interrogano un parziale. Se ad esempio devo aggiungere un metodo mapper per eseguire un carico elaborato che non viene generato, lo aggiungo alla classe personalizzata.

Alla fine il programmatore che utilizza il livello dati nel livello aziendale vede solo una classe con tutte le funzionalità di cui ha bisogno. E se l'origine dati cambia, le parti generiche possono essere facilmente generate senza sovrascrivere elementi personalizzati.

Ho appena trovato un uso per le classi parziali. Ho una classe [DataContract] che utilizzo per passare i dati al client. Volevo che il client fosse in grado di visualizzare la classe in un modo specifico (output di testo). così ho creato una classe parziale e sovrascritto il metodo ToString.

A volte potresti trovare all'opera codice terribilmente vecchio che potrebbe rendere quasi impossibile il refactoring in elementi distinti senza rompere il codice esistente.

Quando non ti viene data la possibilità o il tempo di creare un'architettura più genuina, le classi parziali rendono incredibilmente facile separare la logica dove è necessaria. Ciò consente al codice esistente di continuare a utilizzare la stessa architettura mentre si avvicina un passo a un'architettura più concreta.

Ovunque avresti usato sezioni #region prima probabilmente ha più senso come file separati in classi parziali.

Uso personalmente le classi parziali per le classi di grandi dimensioni in cui i membri statici vanno in un file e i membri dell'istanza vanno nell'altro.

EDIT: DSL Tools per Visual Studio utilizza classi parziali.

Pertanto, è una funzionalità utilizzata da molti codici generati automaticamente. Invece di usare #region, il codice generato automaticamente passa a un file e il codice utente (chiamato anche codice personalizzato) passa a un altro e persino in directory diverse in modo che lo sviluppatore non venga confuso con così tanti file privi di significato.

È bello avere questa scelta che è possibile combinare - ma non forzare a usare - con eredità

Inoltre, può essere utile separare la logica di alcune classi tra più directory. Naturalmente, per le macchine, è lo stesso, ma migliora l'esperienza di leggibilità dell'utente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top