Compartilhar via


Controle de versão com as palavras-chave Override e New (Guia de Programação em C#)

A linguagem C# foi projetada para que o controle de versão entre classes base e derivadas em bibliotecas diferentes possa evoluir e manter a compatibilidade com versões anteriores. Isso significa, por exemplo, que a introdução de um novo membro em uma classe base com o mesmo nome de um membro em uma classe derivada é completamente suportada por C# e não leva a um comportamento inesperado. Isso também significa que uma classe deve declarar explicitamente se um método se destina a substituir um método herdado ou se um método é um novo método que oculta um método herdado de nome semelhante.

Em C#, classes derivadas podem conter métodos com o mesmo nome que métodos de classe base.

  • Se o método na classe derivada não for precedido por palavras-chave novas ou de substituição , o compilador emitirá um aviso e o método se comportará como se a new palavra-chave estivesse presente.

  • Se o método na classe derivada for precedido com a new palavra-chave, o método será definido como independente do método na classe base.

  • Se o método na classe derivada for precedido com a override palavra-chave, os objetos da classe derivada chamarão esse método em vez do método de classe base.

  • Para aplicar a override palavra-chave ao método na classe derivada, o método de classe base deve ser definido como virtual.

  • O método de classe base pode ser chamado de dentro da classe derivada usando a base palavra-chave.

  • As overridepalavras-chave , virtuale new também podem ser aplicadas a propriedades, indexadores e eventos.

Por padrão, os métodos C# não são virtuais. Se um método for declarado como virtual, qualquer classe que herda o método poderá implementar sua própria versão. Para tornar um método virtual, o virtual modificador é usado na declaração de método da classe base. A classe derivada pode substituir o método virtual base usando a override palavra-chave ou ocultar o método virtual na classe base usando a new palavra-chave. Se nem a override palavra-chave nem a new palavra-chave forem especificadas, o compilador emitirá um aviso e o método na classe derivada ocultará o método na classe base.

Para demonstrar isso na prática, suponha por um momento que a Empresa A tenha criado uma classe chamada GraphicsClass, que seu programa usa. A seguir está GraphicsClass:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
}

Sua empresa usa essa classe e você a usa para derivar sua própria classe, adicionando um novo método:

class YourDerivedGraphicsClass : GraphicsClass
{
    public void DrawRectangle() { }
}

Seu aplicativo é usado sem problemas até que a Empresa A libere uma nova versão, GraphicsClassque se assemelha ao seguinte código:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
    public virtual void DrawRectangle() { }
}

A nova versão de GraphicsClass agora contém um método chamado DrawRectangle. Inicialmente, nada ocorre. A nova versão ainda é compatível em termos binários com a versão antiga. Qualquer software implantado continuará funcionando, mesmo que a nova classe esteja instalada nesses sistemas de computador. Todas as chamadas existentes para o método DrawRectangle continuarão a referenciar sua versão, em sua classe derivada.

No entanto, assim que você recompilar seu aplicativo usando a nova versão, GraphicsClassreceberá um aviso do compilador CS0108. Este aviso informa que você precisa considerar como deseja que seu DrawRectangle método se comporte em seu aplicativo.

Se você quiser que seu método substitua o novo método de classe base, use a override palavra-chave:

class YourDerivedGraphicsClass : GraphicsClass
{
    public override void DrawRectangle() { }
}

A override palavra-chave garante que todos os objetos derivados YourDerivedGraphicsClass usem a versão de classe derivada de DrawRectangle. Objetos derivados de YourDerivedGraphicsClass ainda podem acessar a versão da classe base de DrawRectangle usando a palavra-chave base:

base.DrawRectangle();

Se você não quiser que seu método substitua o novo método de classe base, as considerações a seguir se aplicam. Para evitar confusão entre os dois métodos, você pode renomear seu método. Isso pode ser demorado e propenso a erros, e apenas não prático em alguns casos. No entanto, se o projeto for relativamente pequeno, você poderá usar as opções de Refatoração do Visual Studio para renomear o método. Para obter mais informações, consulte Refatorando classes e tipos (Designer de Classe).

Como alternativa, você pode impedir o aviso usando a palavra-chave new em sua definição de classe derivada:

class YourDerivedGraphicsClass : GraphicsClass
{
    public new void DrawRectangle() { }
}

Usar a new palavra-chave informa ao compilador que sua definição oculta a definição contida na classe base. Esse é o comportamento padrão.

Seleção de método e substituição

Quando um método é nomeado em uma classe, o compilador C# seleciona o melhor método para chamar se mais de um método for compatível com a chamada, como quando há dois métodos com o mesmo nome e parâmetros compatíveis com o parâmetro passado. Os seguintes métodos seriam compatíveis:

public class Derived : Base
{
    public override void DoWork(int param) { }
    public void DoWork(double param) { }
}

Quando DoWork for chamado em uma instância de Derived, o compilador C# primeiro tentará tornar a chamada compatível com as versões do DoWork declarado originalmente em Derived. Os métodos de substituição não são considerados como declarados em uma classe, são novas implementações de um método declarado em uma classe base. Somente se o compilador C# não puder corresponder à chamada de método a um método Derivedoriginal, ele tentará corresponder a chamada a um método substituído com o mesmo nome e parâmetros compatíveis. Por exemplo:

int val = 5;
Derived d = new();
d.DoWork(val);  // Calls DoWork(double).

Como a variável val pode ser convertida em um duplo implicitamente, o compilador C# chama DoWork(double) em vez de DoWork(int). Há duas maneiras de evitar isso. Primeiro, evite declarar novos métodos com o mesmo nome que métodos virtuais. Em segundo lugar, você pode instruir o compilador C# a chamar o método virtual para que ele pesquise na lista de métodos da classe base, convertendo a instância de Derived para Base. Como o método é virtual, a implementação de DoWork(int) em Derived será chamada. Por exemplo:

((Base)d).DoWork(val);  // Calls DoWork(int) on Derived.

Para obter mais exemplos de new e override, consulte Saber quando usar substituição e novas palavras-chave.

Consulte também