abatido e abatido

89

Eu sou novo em C # (e OOP ). Quando tenho algum código como o seguinte:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

Pergunta 1 : se eu tiver outro código que faça isso:

   Manager mgr = new Manager();
   Employee emp = (Employee)mgr;

Aqui Employeeestá um Manager, mas quando o lancei assim para um Employee, significa que o estou rejeitando?

Questão 2 :

Quando eu tenho vários Employeeobjetos de classe e alguns, mas não todos, são Manager, como posso fazer o downcast deles quando possível?

user184805
fonte
6
O upcasting pode ser feito sem elenco explícito. Então, Employee emp= mgr;deve ser suficiente.
beije minha axila

Respostas:

95
  1. Está correto. Ao fazer isso, você o está convertendo em um employeeobjeto, o que significa que não pode acessar nada específico do gerenciador.

  2. Downcasting é quando você pega uma aula básica e tenta transformá-la em uma aula mais específica. Isso pode ser feito usando is e um elenco explícito como este:

    if (employee is Manager)
    {
        Manager m = (Manager)employee;
        //do something with it
    }
    

ou com a asoperadora assim:

Manager m = (employee as Manager);
if (m != null)
{
    //do something with it
}

Se algo não estiver claro, terei todo o gosto em corrigi-lo!

RCIX
fonte
Eu preciso de um exemplo para saber o que é Downcasting?
user184805
4
Evite redefinir termos bem estabelecidos: “boxing”, no contexto de OOP e C #, significa algo bastante diferente (= envolver um objeto de tipo de valor em uma referência). Além disso, seu exemplo pode (e deve) usar o asoperador em vez de is, seguido por uma conversão.
Konrad Rudolph,
2
Estou corrigido no primeiro ponto e mudei a segunda metade da minha resposta para mostrar as duas maneiras de fazer isso.
RCIX
3
Sua primeira declaração ("... lançar [uma instância da classe Manager] em um objeto" funcionário "[..] significa que você não pode acessar nada específico do gerente") não é totalmente precisa. No exemplo do OP, se Employee tiver um membro virtual que é substituído no Manager, o CLR chamará a implementação do Manager, independentemente do elenco. Do artigo do MSDN sobre polimorfismo em C #: "Quando uma classe derivada substitui um membro virtual, esse membro é chamado mesmo quando uma instância dessa classe está sendo acessada como uma instância da classe base." O exemplo fornecido pelo MSDN é quase idêntico.
Antony
49

O upcasting (usando (Employee)someInstance) é geralmente fácil, pois o compilador pode informar em tempo de compilação se um tipo é derivado de outro.

No entanto, o downcasting deve ser feito em tempo de execução, pois o compilador nem sempre pode saber se a instância em questão é do tipo fornecido. C # fornece dois operadores para isso - é que lhe diz se as obras baixos, e retornar verdadeiro / falso. E as que tenta fazer a conversão e retorna o tipo correto, se possível, ou nulo, se não.

Para testar se um funcionário é um gerente:

Employee m = new Manager();
Employee e = new Employee();

if(m is Manager) Console.WriteLine("m is a manager");
if(e is Manager) Console.WriteLine("e is a manager");

Você também pode usar este

Employee someEmployee = e  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (e) is a manager");

Employee someEmployee = m  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (m) is a manager");
Preet Sangha
fonte
11
  • Upcasting é uma operação que cria uma referência de classe base a partir de uma referência de subclasse. (subclasse -> superclasse) (ou seja, Gerente -> Funcionário)
  • Downcasting é uma operação que cria uma referência de subclasse a partir de uma referência de classe base. (superclasse -> subclasse) (ou seja, Funcionário -> Gerente)

No seu caso

Employee emp = (Employee)mgr; //mgr is Manager

você está fazendo um upcasting.

Um upcast sempre é bem-sucedido, ao contrário de um downcast que requer uma conversão explícita porque pode falhar potencialmente em tempo de execução ( InvalidCastException ).

C # oferece dois operadores para evitar que essa exceção seja lançada:

Começando de:

Employee e = new Employee();

Primeiro:

Manager m = e as Manager; // if downcast fails m is null; no exception thrown

Segundo:

if (e is Manager){...} // the predicate is false if the downcast is not possible 

Aviso : Quando você faz um upcast, você só pode acessar os métodos da superclasse, propriedades etc ...

vencedor
fonte
6

Caso você precise verificar se cada um dos objetos Employee é um objeto Manager, use o método OfType:

List<Employee> employees = new List<Employee>();

//Code to add some Employee or Manager objects..

var onlyManagers = employees.OfType<Manager>();

foreach (Manager m in onlyManagers) {
  // Do Manager specific thing..
}
HOKBONG
fonte
2

Resposta 1: Sim, é chamado de upcasting, mas a maneira como você faz isso não é moderna. O upcasting pode ser executado implicitamente, você não precisa de nenhuma conversão. Então, basta escrever Employee emp = mgr; é o suficiente para upcasting.

Resposta 2: Se você criar um objeto da classe Manager, podemos dizer que o gerente é um funcionário. Porque a classe Manager: Employee descreve o relacionamento Is-A entre a Classe de Funcionário e a Classe de Gerente. Portanto, podemos dizer que todo gerente é um funcionário.

Mas se criarmos um objeto da classe Employee não podemos dizer que esse funcionário é gerente porque a classe Employee é uma classe que não está herdando nenhuma outra classe. Portanto, você não pode reduzir diretamente esse objeto de Classe de Funcionário para o objeto de Classe de Gerente.

Portanto, a resposta é: se você deseja fazer o downcast do objeto da Classe de Funcionário para o objeto da Classe de Gerente, primeiro você deve ter o objeto da Classe de Gerente primeiro, depois pode fazer o upcast dele e depois fazer o downcast dele.

Asad Patel
fonte
-1

Upcasting e Downcasting:

Upcasting: Casting de Classe Derivada para Classe Base Downcasting: Casting de Classe Base para Classe Derivada

Vamos entender o mesmo como exemplo:

Considere duas classes Shape como minha classe pai e Circle como uma classe derivada, definidas da seguinte maneira:

class Shape
{
    public int Width { get; set; }
    public int Height { get; set; }
}

class Circle : Shape
{
    public int Radius { get; set; }
    public bool FillColor { get; set; }
}

Upcasting:

Forma s = nova forma ();

Círculo c = s;

Ambos c e s estão referenciando o mesmo local de memória, mas ambos têm visualizações diferentes, ou seja, usando a referência "c" você pode acessar todas as propriedades da classe base e classe derivada também, mas usando a referência "s" você pode acessar as propriedades da única classe pai.

Um exemplo prático de upcasting é a classe Stream, que é a classe base de todos os tipos de leitor de stream da estrutura .net:

Leitor StreamReader = novo StreamReader (novo FileStreamReader ());

aqui, FileStreamReader () é atualizado para streadm reder.

Downcasting:

Forma s = novo círculo (); aqui, como explicado acima, a visão de s é o único pai, a fim de torná-lo para ambos, pai e filho, precisamos diminuir

var c = (círculo) s;

O exemplo prático de Downcasting é a classe de botão do WPF.

AutomationNerd
fonte