Classes e métodos parciais (Guia de Programação em C#)

É possível dividir a definição de uma classe, um struct, uma 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.

Aulas parciais

Existem várias situações em que a divisão de uma definição de classe é desejável:

  • Declarar uma classe em arquivos separados permite que vários programadores trabalhem nela ao mesmo tempo.
  • Você pode adicionar código à classe sem ter que recriar o arquivo de origem que inclui o código-fonte gerado automaticamente. O Visual Studio usa essa abordagem quando cria Windows Forms, código wrapper de serviço Web e assim por diante. Você pode criar código que usa essas classes sem ter que modificar o arquivo criado pelo Visual Studio.
  • Os geradores de origem podem gerar funcionalidade extra em uma classe.

Para dividir uma definição de classe, use o modificador de palavra-chave parcial , conforme mostrado aqui:

public partial class Employee
{
    public void DoWork()
    {
    }
}

public partial class Employee
{
    public void GoToLunch()
    {
    }
}

A partial palavra-chave indica que outras partes da classe, struct ou interface podem ser definidas no namespace. Todas as partes devem usar a partial palavra-chave. Todas as peças devem estar disponíveis em tempo de compilação para formar o tipo final. Todas as peças devem ter a mesma acessibilidade, como public, private, e assim por diante.

Se qualquer parte é declarada abstrata, então todo o tipo é considerado abstrato. Se alguma peça for declarada selada, todo o tipo é considerado selado. Se qualquer parte declarar um tipo base, o tipo inteiro herdará essa classe.

Todas as partes que especificam uma classe base devem concordar, mas as partes que omitem uma classe base ainda herdam o tipo base. As partes podem especificar diferentes interfaces de base, e o tipo final implementa todas as interfaces listadas por todas as declarações parciais. Qualquer classe, struct ou membros de interface declarados em uma definição parcial estão disponíveis para todas as outras partes. O tipo final é a combinação de todas as partes em tempo de compilação.

Nota

O partial modificador não está disponível em declarações de delegado ou enumeração.

O exemplo a seguir mostra que os tipos aninhados podem ser parciais, mesmo que o tipo no qual eles estão aninhados não seja parcial.

class Container
{
    partial class Nested
    {
        void Test() { }
    }

    partial class Nested
    {
        void Test2() { }
    }
}

Em tempo de compilação, atributos de definições de tipo parcial são mesclados. Por exemplo, considere as seguintes declarações:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

São equivalentes às seguintes declarações:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

A partir de todas as definições de tipo parcial, são fundidas as seguintes:

  • Comentários XML
  • Interfaces
  • atributos de parâmetros de tipo genérico
  • atributos de classe
  • membros

Por exemplo, considere as seguintes declarações:

partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }

São equivalentes às seguintes declarações:

class Earth : Planet, IRotate, IRevolve { }

Restrições

Há várias regras a serem seguidas quando você estiver trabalhando com definições parciais de classe:

  • Todas as definições de tipo parcial destinadas a serem partes do mesmo tipo devem ser modificadas com partial. Por exemplo, as seguintes declarações de classe geram um erro:
    public partial class A { }
    //public class A { }  // Error, must also be marked partial
    
  • O partial modificador só pode aparecer imediatamente antes da palavra-chave class, structou interface.
  • Tipos parciais aninhados são permitidos em definições de tipo parcial, conforme ilustrado no exemplo a seguir:
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • Todas as definições de tipo parcial destinadas a serem partes do mesmo tipo devem ser definidas no mesmo conjunto e no mesmo módulo (.exe ou .dll arquivo). As definições parciais não podem abranger vários módulos.
  • O nome da classe e os parâmetros de tipo genérico devem corresponder em todas as definições de tipo parcial. Os tipos genéricos podem ser parciais. Cada declaração parcial deve usar os mesmos nomes de parâmetros na mesma ordem.
  • As seguintes palavras-chave em uma definição de tipo parcial são opcionais, mas se estiverem presentes em uma definição de tipo parcial, não podem entrar em conflito com as palavras-chave especificadas em outra definição parcial para o mesmo tipo:

Para obter mais informações, consulte Restrições em parâmetros de tipo.

Exemplos

No exemplo a seguir, os campos e o construtor da classe, Coords, são declarados em uma definição de classe parcial, e o membro, PrintCoords, é declarado em outra definição de classe parcial.

public partial class Coords
{
    private int x;
    private int y;

    public Coords(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public partial class Coords
{
    public void PrintCoords()
    {
        Console.WriteLine("Coords: {0},{1}", x, y);
    }
}

class TestCoords
{
    static void Main()
    {
        Coords myCoords = new Coords(10, 15);
        myCoords.PrintCoords();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: Coords: 10,15

O exemplo a seguir mostra que você também pode desenvolver estruturas parciais e interfaces.

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

Métodos parciais

Uma classe parcial ou struct pode conter um método parcial. Uma parte da classe contém a assinatura do método. Uma implementação pode ser definida na mesma parte ou noutra parte.

Uma implementação não é necessária para um método parcial quando a assinatura obedece às seguintes regras:

  • A declaração não inclui modificadores de acesso. O método tem private acesso por padrão.
  • O tipo de retorno é void.
  • Nenhum dos parâmetros tem o out modificador.
  • A declaração de método não pode incluir nenhum dos seguintes modificadores:

O método e todas as chamadas para o método são removidas em tempo de compilação quando não há implementação.

Qualquer método que não esteja em conformidade com todas essas restrições (por exemplo, public virtual partial void método), deve fornecer uma implementação. Essa implementação pode ser fornecida por um gerador de fontes.

Os métodos parciais permitem que o implementador de uma parte de uma classe declare um método. O implementador de outra parte da classe pode definir esse método. Há dois cenários em que essa separação é útil: modelos que geram código clichê e geradores de código-fonte.

  • Código do modelo: O modelo reserva um nome e uma assinatura do método para que o código gerado possa chamar o método. Esses métodos seguem as restrições que permitem que um desenvolvedor decida se deseja implementar o método. Se o método não for implementado, o compilador removerá a assinatura do método e todas as chamadas para o método. As chamadas para o método, incluindo quaisquer resultados que ocorreriam a partir da avaliação de argumentos nas chamadas, não têm efeito em tempo de execução. Portanto, qualquer código na classe parcial pode usar livremente um método parcial, mesmo que a implementação não seja fornecida. Nenhum erro em tempo de compilação ou de execução resulta se o método for chamado, mas não implementado.
  • Geradores de código-fonte: Os geradores de código-fonte fornecem uma implementação para métodos. O desenvolvedor humano pode adicionar a declaração de método (geralmente com atributos lidos pelo gerador de código-fonte). O desenvolvedor pode escrever código que chama esses métodos. O gerador de código-fonte é executado durante a compilação e fornece a implementação. Nesse cenário, as restrições para métodos parciais que podem não ser implementados geralmente não são seguidas.
// Definition in file1.cs
partial void OnNameChanged();

// Implementation in file2.cs
partial void OnNameChanged()
{
  // method body
}
  • As declarações de método parcial devem começar com a palavra-chave contextual parcial.
  • As assinaturas do método parcial em ambas as partes do tipo parcial devem corresponder.
  • Os métodos parciais podem ter modificadores estáticos e inseguros .
  • Os métodos parciais podem ser genéricos. As restrições devem ser as mesmas na declaração do método de definição e implementação. Os nomes dos parâmetros e dos parâmetros de tipo não precisam ser os mesmos na declaração de implementação e na declaração de definição.
  • Você pode fazer um delegado para um método parcial definido e implementado, mas não para um método parcial que não tenha uma implementação.

Especificação da linguagem C#

Para obter mais informações, consulte Tipos parciais e métodos parciais na Especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso do C#. Os recursos adicionais para métodos parciais são definidos na especificação do recurso.

Consulte também