Pergunta

Quais são as diferenças entre declarando um método em um tipo de base "virtual" e, em seguida, substituindo-lo em um tipo de criança que usa a palavra-chave "override" ao invés de simplesmente usar a palavra-chave "new" quando declarar o método de correspondência no tipo de criança ?

Foi útil?

Solução

A palavra-chave "novo" não substitui, significa um novo método que não tem nada a ver com o método da classe base.

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}

Isto imprime falsa, se você usou substituição seria impresso verdade.

(código de base tirada de Joseph Daigle)

Então, se você está fazendo polimorfismo real, você deve sempre substituem . O único lugar onde você precisa usar "nova" é quando o método não está relacionado de alguma forma para a versão da classe base.

Outras dicas

Eu sempre encontrar coisas como esta mais facilmente compreendido com imagens:

Mais uma vez, tendo o código de Joseph Daigle,

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}

Se você, em seguida, chamar o código como este:

Foo a = new Bar();
a.DoSomething();

NOTA: O importante é que o nosso objeto é realmente uma Bar, mas somos armazenando-o em uma variável do tipo Foo (isso é semelhante ao convertê-lo)

Em seguida, o resultado será o seguinte, dependendo se você usou virtual / override ou new ao declarar suas classes.

imagem explicação / Override Virtual

Aqui está algum código para entender a diferença no comportamento dos métodos virtuais e não-virtuais:

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}

A palavra-chave new realmente cria um novo membro que só existe nesse tipo específico.

Por exemplo

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

O método existe em ambos os tipos. Quando você usa reflexão e obter os membros do tipo Bar, na verdade você vai encontrar 2 métodos chamados DoSomething() que parecem exatamente o mesmo. Usando new você esconde eficazmente a implementação da classe base, de modo que quando as classes derivam Bar (no meu exemplo), a chamada de método para base.DoSomething() vai para Bar e não Foo.

/ virtuais override informa ao compilador que os dois métodos estão relacionados e que, em algumas circunstâncias, quando você acha que você está chamando o primeiro método (virtual) é realmente correto chamar o segundo (substituído) método em vez disso. Este é o fundamento de polimorfismo.

(new SubClass() as BaseClass).VirtualFoo()

irá chamar o método VirtualFoo anulado da subclasse ().

new informa ao compilador que você está adicionando um método para uma classe derivada com o mesmo nome de um método na classe base, mas eles não têm nenhuma relação entre si.

(new SubClass() as BaseClass).NewBar()

Será que a chamada do ClasseBase NewBar () método, Considerando o seguinte:

(new SubClass()).NewBar()

irá chamar o método de SubClass NewBar ().

Além de apenas os detalhes técnicos, Acho que usando / override virtual comunica uma grande quantidade de informação semântica sobre o design. Quando você declarar um método virtual, você indicar que você espera que as classes de aplicação pode querer fornecer suas próprias implementações, não-padrão. Omitir esta em uma classe base, da mesma forma, declara a expectativa de que o método padrão deve ser suficiente para todas as classes de execução. Da mesma forma, pode-se usar declarações abstratas para forçar as classes que implementam a fornecer sua própria implementação. Mais uma vez, penso que este se comunica muito sobre como o programador espera que o código a ser usado. Se eu estivesse escrevendo tanto a base e implementação de classes e encontrei-me com nova eu ??repensar seriamente a decisão de não fazer o método virtual no pai e declarar minha intenção especificamente.

A diferença entre a palavra-chave override e nova palavra-chave é que o primeiro faz método de substituição e mais tarde faz método esconderijo.

Confira os links folllowing para mais informações ...

MSDN e Outros

  • palavra-chave new é para esconder. - significa que você está escondendo o seu método em tempo de execução. A saída será baseada método de classe base.
  • override para substituir. - meios você está invocando o seu método de classe derivada com a referência de classe base. A saída será baseada no método de classe derivada.

Minha versão de explicação vem de usar Propriedades para ajudar a compreender as diferenças.

override é bastante simples, certo? O tipo subjacente substituições do pai.

new é talvez a enganosa (para mim foi). Com propriedades é mais fácil de entender:

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

Usando um depurador você pode notar que Foo foo tem 2 Propriedades GetSomething, como ele realmente tem 2 versões da propriedade, Foo de e Bar de, e para saber qual usar, c # "picaretas" o propriedade para o tipo atual.

Se você quiser usar a versão do bar, você teria override usado ou uso Foo foo vez.

Bar bar tem apenas 1 , como ele quer completamente new comportamento para GetSomething.

Não marcando um método com algum significado: Bind este método usando o tipo de compilação do objeto, não tipo de tempo de execução (ligação estática).

A marcação de um método com meios virtual: Liga este método, utilizando o tipo de execução do objecto, tipo tempo de compilação não (ligação dinâmica).

Marcação um método virtual classe base com override em meios de classe derivados: Este é o método para ser ligado usando o tipo de execução do objecto (ligação dinâmica).

A marcação de um método de classe base virtual com new no meio da classe derivada: Este é um método novo, que não tem relação com o outro com o mesmo nome na classe base e deve ser vinculado usando o tipo de tempo de compilação do objeto (ligação estática ).

Não marcando um método de classe virtual de base nos meios da classe derivada: Este método está marcado como (ligação estática) new.

A marcação de um método significa abstract: Este método é virtual, mas não vou declarar um corpo para ele e sua classe também é abstrata (ligação dinâmica).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top