Controle de versão com a substituição e novas palavras-chave (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 pelo 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 com nome semelhante.
Em C#, as classes derivadas podem conter métodos com o mesmo nome que os 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 é precedido com a
new
palavra-chave, o método é definido como sendo 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 virtual.O método de classe base pode ser chamado de dentro da classe derivada usando a
base
palavra-chave.O
override
,virtual
enew
as palavras-chave 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 herde 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 então 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, assuma por um momento que a Empresa A criou uma classe chamada GraphicsClass
, que seu programa usa. O seguinte é 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 do GraphicsClass
, que se assemelha ao seguinte código:
class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
public virtual void DrawRectangle() { }
}
A nova versão do GraphicsClass
agora contém um método chamado DrawRectangle
. Inicialmente, nada ocorre. A nova versão ainda é binária compatível com a versão antiga. Qualquer software que você tenha implantado continuará a funcionar, mesmo que a nova classe esteja instalada nesses sistemas de computador. Quaisquer chamadas existentes para o método DrawRectangle
continuarão a fazer referência à sua versão, na sua classe derivada.
No entanto, assim que você recompilar seu aplicativo usando a nova versão do GraphicsClass
, você receberá um aviso do compilador, CS0108. Este aviso informa-o de que tem de considerar como pretende que o seu DrawRectangle
método se comporte na sua aplicação.
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 usarão a versão de YourDerivedGraphicsClass
classe derivada do DrawRectangle
. Os objetos derivados de YourDerivedGraphicsClass
ainda podem acessar a versão da classe base usando DrawRectangle
a palavra-chave base:
base.DrawRectangle();
Se você não quiser que seu método substitua o novo método de classe base, as seguintes considerações 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 simplesmente não é prático em alguns casos. No entanto, se seu projeto for relativamente pequeno, você pode usar as opções de refatoração do Visual Studio para renomear o método. Para obter mais informações, consulte Refatoração de classes e tipos (Class Designer).
Como alternativa, você pode evitar o aviso usando a palavra-chave new
em sua definição de classe derivada:
class YourDerivedGraphicsClass : GraphicsClass
{
public new void DrawRectangle() { }
}
O uso da new
palavra-chave informa ao compilador que sua definição oculta a definição contida na classe base. Este é o comportamento predefinido.
Substituição e seleção de método
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 que são 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
é chamado em uma instância do Derived
, o compilador C# primeiro tentará tornar a chamada compatível com as versões do declarado DoWork
originalmente em Derived
. Os métodos de substituição não são considerados como declarados em uma classe, eles são novas implementações de um método declarado em uma classe base. Somente se o compilador C# não puder corresponder a chamada de método a um método original no Derived
, 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 Derived();
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 dos métodos virtuais. Em segundo lugar, você pode instruir o compilador C# a chamar o método virtual fazendo com que ele pesquise a lista de métodos de classe base convertendo a instância de Derived
para Base
. Como o método é virtual, a implementação do DoWork(int)
on Derived
será chamada. Por exemplo:
((Base)d).DoWork(val); // Calls DoWork(int) on Derived.
Para obter mais exemplos de new
e , consulte Saber quando usar a substituição e novas palavras-chaveoverride
.