C#
- Apresentando Partial Class
![]() |
Neste artigo vou apresentar o conceito de Partial Class na linguagem C#. |
Na linguagem C# , quando você cria uma classe concreta você a define usando a seguinte sintaxe:
<modificador de acesso> class <nome da classe>
{
<construtor>
<campos>
<propriedades>
<métodos>
<eventos>
<delegates>
<indexadores>
<classe aninhadas>
}
|
De forma resumida uma classe é definida pela palavra reservada class seguida de seu nome e o corpo da classe é definido dentro das chaves {....} onde definimos os membros da classe.
Exemplo:
public class MinhaClasse
{
<membros>
}
|
Quando definimos uma classe usando essa sintaxe, temos que definir em um único arquivo físico com extensão .cs, todos os membros da classe. Dessa forma não podemos declarar uma classe em dois arquivos separados em um mesmo projeto.
A partir da versão 2.0 a plataforma .NET introduziu o recurso chamado partial class que permite ter uma única classe ser implementada em múltiplos arquivos físicos com extensão .cs.
Desta forma é possível dividir a definição de uma classe, struct ou interface ou um método em dois ou mais arquivos de origem. Cada arquivo de origem contém uma seção da definição de tipo ou método e todas as partes são combinadas quando o aplicativo é compilado.
Isso é feito usando o modificador partial que pode ser aplicado em uma classe, método, interface e struct.
Usando o conceito de partial class você pode dividir a definição de sua classe em mais de um arquivo físico.
Logicamente não há diferença alguma para o compilador pois quando uma partial class é compilada o compilador agrupa todos os arquivos da classe parcial gerando uma única entidade.(O código da linguagem intermediária formado é o mesmo).
Assim vamos criar a classe parcial MinhaClasseParcial em dois arquivos físicos diferentes:
MinhaClassePropriedades.cs
public partial class MinhaClasseParcial
{
public DateTime DataNascimento { get; set; }
public string Nome { get; set; }
}
|
MinhaClasseMetodos.cs
public partial class MinhaClasseParcial { public TimeSpan CalculaIdade(DateTime DataNascimento) { return (DateTime.Now.Date - DataNascimento); } } |
Acima temos a definição de uma partial class em dois arquivos físicos distintos:
Após a compilação será gerada a classe MinhaClasseParcial:
public class MinhaClasseParcial { public DateTime DataNascimento { get; set; } public string Nome { get; set; } public TimeSpan CalculaIdade(DateTime DataNascimento)
|
A seguir outros exemplos do uso do modificador partial
1. Separar a implementação de uma interface
public
interface
IMinhaInterface { void Metodo1(); } public partial class MinhaClasse : IMinhaInterface{ public void Metodo1() { Console.WriteLine("Método1"); } } public partial class MinhaClasse{ public void Metodo2() { Console.WriteLine("Método2"); } } |
Neste exemplo, a interface IMinhaInterface é implementada pela classe MinhaClasse. A implementação do método Metodo1 é definida em uma parte da classe MinhaClasse, enquanto a implementação do método Metodo2 é definida em outra parte. Dessa forma, a implementação da interface é separada da implementação de outros membros da classe.
2. Separar a definição de propriedades
public
partial
class
MinhaClasse { private int _idade; public int Idade { get { return _idade; } set { _idade = value; } } } public partial class MinhaClasse{ public string Nome { get; set; } } |
Neste exemplo, a classe MinhaClasse define duas propriedades, Idade e Nome, que são definidas em partes diferentes da classe. A propriedade Idade tem um getter e um setter personalizados, enquanto a propriedade Nome usa a sintaxe simplificada para definir um getter e um setter.
3. Separar a definição de eventos
public
partial
class
MinhaClasse { public event EventHandler MeuEvento; private void RaiseMeuEvento() { MeuEvento?.Invoke(this, EventArgs.Empty); } } public partial class MinhaClasse{ public void FazAlgo() { // faz algo aqui RaiseMeuEvento(); } } |
Neste exemplo, a classe MinhaClasse define um evento MeuEvento que é disparado pelo método RaiseMeuEvento. O método FazAlgo() é definido em outra parte da classe e usa o método RaiseMeuEvento para disparar o evento. Dessa forma, a definição do evento é separada da implementação do método que o usa.
Vantagens e regras de uso
Uma das vantagens em se utilizar as Partial Class é poder separar a lógica de negócio da interface de usuário em arquivos distintos facilitando a manutenção e o trabalho em equipe. (Será..??)
Algumas regras que devemos ter mente ao usar as classes parciais:
A seguir vemos exemplos que ilustram a aplicação destas regras a partir da terceira regra:
3. Se qualquer parte for declarada abstract, sealed ou base type então toda a classe será declarada do mesmo tipo
public
partial
class
MinhaClasse { // código da primeira parte da classe } public partial class MinhaClasse{ // código da segunda parte da classe // declarando um método abstrato na segunda parte public abstract void MeuMetodo(); } |
Neste exemplo, a primeira parte da classe MinhaClasse não tem modificador de acesso e não define nenhum membro. Já a segunda parte define um método abstrato MeuMetodo().
Como o método é abstrato, a classe inteira será considerada como abstrata.
4. O modificador partial somente pode ser usado antes da palavra-chave class, struct ou interface
// erro de
compilação partial enum MeuEnum { // código da primeira parte do enum } public partial class MinhaClasse{ // código da primeira parte da classe } // erro de
compilação
|
Neste exemplo, há um erro de compilação ao tentar usar partial com uma definição de enum ou delegate. Isso acontece porque o modificador partial só pode ser usado antes de class, struct ou interface.
5. Tipos parciais aninhados são permitidos
public
partial
class
MinhaClasse { // código da primeira parte da classe public partial class MinhaClasseAninhada { // código da primeira parte da classe aninhada } } public partial class MinhaClasse{ // código da segunda parte da classe public partial class MinhaClasseAninhada { // código da segunda parte da classe aninhada } } |
Neste exemplo, a classe MnhaClasse tem uma classe aninhada MinhaClasseAninhada. A definição da classe aninhada é dividida em duas partes separadas. A primeira parte é definida na primeira parte da classe MinhaClasse, enquanto a segunda parte é definida na segunda parte da classe.
6. Os atributos se aplicam a todas as partes da classe
[Serializable] public partial class MinhaClasse { // código da primeira parte da classe } public partial class MinhaClasse{ // código da segunda parte da classe } |
Neste exemplo, a classe MinhaClasse tem o atributo [Serializable] aplicado a ela na primeira parte da classe. Como o atributo se aplica a toda a classe, a segunda parte da classe também será considerada serializável.
7.As características definidas em qualquer parte estão disponíveis para todas as partes das classes;
public
partial
class
MinhaClasse { private int _meuInt; public void SetMeuInt(int valor) { _meuInt = valor; } } public partial class MinhaClasse{ public void ImprimirMeuInt() { Console.WriteLine(_meuInt); } } |
Neste exemplo, a classe MinhaClasse é definida em duas partes. A primeira parte define uma variável privada _meuInt e um método SetMeuInt para configurar o valor da variável. A segunda parte define um método ImprimirMeuInt que imprime o valor da variável _meuInt.
Observe que a variável _meuInt é definida na primeira parte da classe, mas é usada na segunda parte da classe no método ImprimirMeuInt . Isso é possível porque as características definidas em qualquer parte estão disponíveis para todas as partes da classe. Dessa forma, a segunda parte da classe pode acessar a variável _meuInt definida na primeira parte da classe sem nenhum problema.
Na figura abaixo vemos que a instância da classe parcial MinhaClasseParcial tem acesso a todos os membros definidos em cada parte:
Utilização das classes parciais e boas práticas
Assim, as classes parciais são geralmente usadas com códigos gerados por alguma ferramenta, de forma a permitir que o programador injete código dentro dessa classe gerada, sem ter de alterar o arquivo de código gerado.
Usar classes parciais em um código não gerado, faz com que o código fique confuso.
Um dos princípios SOLID , o princípio SRP, reza que uma mesma classe de não deve ter diversas funções.
Dessa forma, não estaria a utilização do recurso partial class violando esse princípio SOLID, quando usado apenas para esse propósito ?
Use, quando estritamente necessário, e não abuse.
E estamos conversados...
"Portanto, agora
nenhuma condenação há para os que estão em Cristo Jesus, que não andam segundo a
carne, mas segundo o Espírito."
Romanos 8:1
Referências: