przygnębiony i przygnębiony

88

Jestem nowy w C # (i OOP ). Kiedy mam kod podobny do następującego:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

Pytanie 1 : Jeśli mam inny kod, który to robi:

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

Oto Employeea Manager, ale kiedy Employeerzucam to w ten sposób na to, oznacza to, że go podrzucam?

Pytanie 2 :

Kiedy mam kilka Employeeobiektów klasowych, a niektóre z nich są, ale nie wszystkie Manager, jak mogę je zdegradować, jeśli to możliwe?

user184805
źródło
6
Nadawanie można wykonać bez jawnej obsady. To Employee emp= mgr;powinno wystarczyć.
pocałuj mnie w pachę

Odpowiedzi:

93
  1. To jest poprawne. Kiedy to robisz, wrzucasz go do employeeobiektu, co oznacza, że ​​nie możesz uzyskać dostępu do niczego konkretnego menedżera.

  2. Downcasting polega na tym, że bierzesz klasę bazową, a następnie próbujesz przekształcić ją w bardziej szczegółową klasę. Można to osiągnąć za pomocą is i wyraźnego rzutowania w następujący sposób:

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

lub z takim asoperatorem:

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

Jeśli coś jest niejasne, z przyjemnością to poprawię!

RCIX
źródło
Potrzebuję przykładu, aby wiedzieć, co to jest Downcasting?
user184805
4
Unikaj ponownego definiowania dobrze ugruntowanych terminów: „opakowanie” w kontekście OOP i C # oznacza coś raczej innego (= zawijanie obiektu typu wartości w odwołanie). Ponadto Twój przykład może (i powinien) używać asoperatora zamiast is, po którym następuje rzutowanie.
Konrad Rudolph
2
Stoję poprawiony w pierwszym punkcie i zmieniłem drugą połowę mojej odpowiedzi, aby pokazać oba sposoby zrobienia tego.
RCIX
2
Twoje pierwsze stwierdzenie („… rzutowanie [instancji klasy Manager] na obiekt„ pracownika ”[…] oznacza, że ​​nie możesz uzyskać dostępu do niczego konkretnego menedżera”) nie jest całkowicie dokładne. W przykładzie OP, jeśli pracownik ma członka wirtualnego, który jest zastępowany w Menedżerze, środowisko CLR wywoła implementację Menedżera, niezależnie od rzutowania. Z artykułu MSDN na temat polimorfizmu w języku C #: „Gdy klasa pochodna zastępuje wirtualny element członkowski, ten element członkowski jest wywoływany nawet wtedy, gdy do wystąpienia tej klasy uzyskuje się dostęp jako wystąpienie klasy bazowej”. Przykład podany przez MSDN jest prawie identyczny.
Antony
49

Uaktualnianie (używanie (Employee)someInstance) jest ogólnie łatwe, ponieważ kompilator może powiedzieć w czasie kompilacji, czy typ pochodzi od innego.

Jednak generowanie downcastingu musi być wykonywane w czasie wykonywania, ponieważ kompilator może nie zawsze wiedzieć, czy dana instancja jest podanego typu. C # udostępnia dwa podmioty do tego - to , które mówi, jeśli prace spuszczonymi i powrócić prawda / fałsz. I jak który próbuje wykonać rzutowanie i zwraca poprawny typ, jeśli to możliwe, lub null, jeśli nie.

Aby sprawdzić, czy pracownik jest menedżerem:

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");

Możesz również użyć tego

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
źródło
11
  • Upcasting to operacja, która tworzy odwołanie do klasy bazowej z odwołania do podklasy. (subclass -> superclass) (tj. Manager -> Pracownik)
  • Downcasting to operacja, która tworzy odwołanie do podklasy z odwołania do klasy bazowej. (superclass -> subclass) (tj. Pracownik -> Menedżer)

W Twoim przypadku

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

robisz upcasting.

Upcast zawsze kończy się sukcesem, w przeciwieństwie do downcast, który wymaga jawnego rzutowania, ponieważ może potencjalnie zakończyć się niepowodzeniem w czasie wykonywania ( InvalidCastException ).

C # oferuje dwa operatory, aby uniknąć wyrzucenia tego wyjątku:

Zaczynając od:

Employee e = new Employee();

Pierwszy:

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

Druga:

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

Ostrzeżenie : kiedy robisz upcast, masz dostęp tylko do metod, właściwości nadklasy itp ...

zwycięzca
źródło
6

W przypadku konieczności sprawdzenia każdego obiektu Employee, czy jest to obiekt Manager, użyj metody 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
źródło
2

Odpowiedź 1: Tak, nazywa się to upcastingiem, ale sposób, w jaki to robisz, nie jest nowoczesny. Nadawanie można wykonać niejawnie, nie potrzebujesz żadnej konwersji. Więc po prostu piszesz Pracownik emp = mgr; wystarczy do podniecenia.

Odpowiedź 2: Jeśli tworzysz obiekt klasy Manager, możemy powiedzieć, że menedżer jest pracownikiem. Ponieważ klasa Manager: Employee przedstawia relację IS -A pomiędzy klasą pracownika a klasą menedżera. Można więc powiedzieć, że każdy menedżer jest pracownikiem.

Ale jeśli tworzymy obiekt klasy Employee, nie możemy powiedzieć, że ten pracownik jest menedżerem, ponieważ klasa Employee to klasa, która nie dziedziczy żadnej innej klasy. Dlatego nie można bezpośrednio przenieść tego obiektu klasy pracownika do obiektu klasy menedżera.

Więc odpowiedź jest taka, że ​​jeśli chcesz zdegradować obiekt klasy pracownika do obiektu klasy menedżera, najpierw musisz mieć obiekt klasy menedżera, następnie możesz go przesłać do góry, a następnie możesz go zdegradować.

Asad Patel
źródło
-1

Upcasting i Downcasting:

Upcasting: rzutowanie z klasy pochodnej do klasy podstawowej. Downcasting: rzutowanie z klasy bazowej do klasy pochodnej

Rozumiemy to samo, co na przykładzie:

Rozważ dwie klasy Shape jako Moja klasa nadrzędna i Circle jako klasę pochodną, ​​zdefiniowane w następujący sposób:

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; }
}

Nadawanie:

Kształt s = nowy Kształt ();

Okrąg c = s;

Zarówno c, jak i s odnoszą się do tej samej lokalizacji w pamięci, ale oba mają różne widoki tzn. Używając odwołania "c" możesz również uzyskać dostęp do wszystkich właściwości klasy bazowej i pochodnej, ale używając odnośnika "s" możesz uzyskać dostęp do właściwości jedynej klasy nadrzędnej.

Praktycznym przykładem upcastingu jest klasa Stream, która jest klasą bazową wszystkich typów czytników strumieniowych frameworka .net:

StreamReader reader = new StreamReader (new FileStreamReader ());

tutaj FileStreamReader () jest upcastowany do reder streadm.

Downcasting:

Kształt s = nowy okrąg (); tutaj, jak wyjaśniono powyżej, widok s jest jedynym rodzicem, aby uczynić go zarówno dla rodzica, jak i dziecka, musimy go obniżyć

var c = (Circle) s;

Praktycznym przykładem Downcasting jest klasa przycisku WPF.

AutomationNerd
źródło