downcast và upcast


88

Tôi mới sử dụng C # (và OOP ). Khi tôi có một số mã như sau:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

Câu hỏi 1 : Nếu tôi có mã khác thực hiện điều này:

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

Đây Employeelà một Manager, nhưng khi tôi chuyển nó như vậy sang một Employeenó có nghĩa là tôi đang dự báo nó?

Câu hỏi 2 :

Khi tôi có một số Employeeđối tượng lớp và một số nhưng không phải là tất cả chúng Manager, làm thế nào tôi có thể hủy bỏ chúng nếu có thể?


6
Dự báo có thể được thực hiện mà không cần diễn viên rõ ràng. Vì vậy, Employee emp= mgr;nên đủ.
hôn nách của tôi

Câu trả lời:


93
  1. Đúng rồi. Khi bạn làm điều đó, bạn đang truyền nó thành một employeeđối tượng, vì vậy điều đó có nghĩa là bạn không thể truy cập bất kỳ thứ gì cụ thể của trình quản lý.

  2. Downcasting là nơi bạn lấy một lớp cơ sở, sau đó thử và biến nó thành một lớp cụ thể hơn. Điều này có thể được thực hiện với việc sử dụng is và cast rõ ràng như thế này:

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

hoặc với asnhà điều hành như thế này:

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

Nếu có gì chưa rõ, tôi sẽ sẵn lòng sửa lại!


Tôi cần ví dụ để biết Downcasting là gì?
user184805

4
Tránh xác định lại các thuật ngữ đã được thiết lập tốt: “quyền anh”, trong ngữ cảnh của OOP và C #, có nghĩa là một cái gì đó khá khác (= gói một đối tượng loại giá trị vào một tham chiếu). Ngoài ra, ví dụ của bạn có thể (và nên) sử dụng astoán tử thay vì is, theo sau là một phép ép kiểu.
Konrad Rudolph

2
Tôi đã sửa ở điểm đầu tiên, và tôi đã thay đổi nửa sau của câu trả lời của mình để chỉ ra cả hai cách làm.
RCIX

2
Câu lệnh đầu tiên của bạn ("... truyền [một thể hiện của lớp Trình quản lý] thành một đối tượng" nhân viên "[..] có nghĩa là bạn không thể truy cập bất kỳ thứ gì cụ thể của người quản lý") là không hoàn toàn chính xác. Trong ví dụ của OP, nếu Nhân viên có một thành viên ảo bị ghi đè trong Trình quản lý, CLR sẽ gọi việc triển khai Trình quản lý, bất chấp việc ép kiểu. Từ bài báo MSDN về tính đa hình trong C #: "Khi một lớp dẫn xuất ghi đè một thành viên ảo, thành viên đó được gọi ngay cả khi một thể hiện của lớp đó đang được truy cập như một thể hiện của lớp cơ sở." Ví dụ do MSDN cung cấp gần như giống hệt nhau.
Antony

49

Việc nâng cấp (sử dụng (Employee)someInstance) nói chung là dễ dàng vì trình biên dịch có thể cho bạn biết tại thời điểm biên dịch nếu một kiểu có nguồn gốc từ kiểu khác.

Tuy nhiên, việc Downcasting thường phải được thực hiện tại thời điểm chạy vì trình biên dịch có thể không phải lúc nào cũng biết liệu phiên bản được đề cập có thuộc loại đã cho hay không. C # cung cấp hai nhà khai thác cho điều này - mà cho bạn biết nếu các công trình yếu hèn, và trở về đúng / sai. Và khi nào cố gắng ép kiểu và trả về kiểu chính xác nếu có thể, hoặc null nếu không.

Để kiểm tra xem một nhân viên có phải là người quản lý hay không:

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

Bạn cũng có thể sử dụng cái này

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

11
  • Upcasting là một hoạt động tạo ra một tham chiếu lớp cơ sở từ một tham chiếu lớp con. (subclass -> superclass) (tức là Manager -> Employee)
  • Downcasting là một hoạt động tạo ra một tham chiếu lớp con từ một tham chiếu lớp cơ sở. (lớp cha -> lớp con) (tức là Nhân viên -> Người quản lý)

Trong trường hợp của bạn

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

bạn đang thực hiện một dự báo.

Một upcast luôn thành công không giống như một downcast yêu cầu một kiểu truyền rõ ràng vì nó có thể thất bại trong thời gian chạy. ( InvalidCastException ).

C # cung cấp hai toán tử để tránh trường hợp ngoại lệ này được ném ra:

Bắt đầu từ:

Employee e = new Employee();

Đầu tiên:

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

Thứ hai:

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

Cảnh báo : Khi bạn thực hiện một upcast, bạn chỉ có thể truy cập vào các phương thức, thuộc tính của lớp cha, v.v.


6

Trong trường hợp bạn cần kiểm tra từng đối tượng Employee xem nó có phải là đối tượng Manager hay không, hãy sử dụng phương thức 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..
}

2

Trả lời 1: Có, nó được gọi là upcasting nhưng cách bạn làm không phải là cách hiện đại. Dự báo có thể được thực hiện ngầm mà bạn không cần bất kỳ chuyển đổi nào. Vì vậy, chỉ cần viết Employee emp = mgr; là đủ để dự báo.

Trả lời 2: Nếu bạn tạo đối tượng của lớp Manager, chúng ta có thể nói rằng manager là một nhân viên. Vì class Manager: Nhân viên mô tả mối quan hệ Is-A giữa Lớp nhân viên và Lớp người quản lý. Vì vậy, chúng ta có thể nói rằng mọi nhà quản lý đều là một nhân viên.

Nhưng nếu chúng ta tạo đối tượng của lớp Employee, chúng ta không thể nói rằng nhân viên này là manager vì lớp Employee là một lớp không kế thừa bất kỳ lớp nào khác. Vì vậy, bạn không thể downcast trực tiếp đối tượng Lớp nhân viên đó xuống đối tượng Lớp quản lý.

Vì vậy, câu trả lời là, nếu bạn muốn downcast từ đối tượng Lớp nhân viên xuống đối tượng Lớp người quản lý, trước tiên bạn phải có đối tượng của Lớp người quản lý trước rồi bạn có thể upcast nó và sau đó bạn có thể downcast nó.


-1

Upcasting và Downcasting:

Nâng cấp: Truyền từ Lớp gốc sang Lớp Cơ sở Hạ cấp: Truyền từ Lớp Cơ sở sang Lớp gốc

Hãy hiểu tương tự như một ví dụ:

Hãy xem xét hai lớp Shape là lớp cha của tôi và Circle là lớp Bắt nguồn, được định nghĩa như sau:

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

Dự báo:

Shape s = new Shape ();

Đường tròn c = s;

Cả c và s đều tham chiếu đến cùng một vị trí bộ nhớ, nhưng cả hai đều có các khung nhìn khác nhau, tức là sử dụng tham chiếu "c" bạn có thể truy cập tất cả các thuộc tính của lớp cơ sở và lớp dẫn xuất nhưng sử dụng tham chiếu "s" bạn có thể truy cập thuộc tính của lớp cha duy nhất.

Một ví dụ thực tế về upcasting là lớp Stream là lớp cơ sở của tất cả các loại trình đọc luồng của khung .net:

Trình đọc StreamReader = new StreamReader (FileStreamReader mới ());

ở đây, FileStreamReader () được đưa lên để tạo lập trình liên tục.

Hạ cấp:

Hình dạng s = new Circle (); ở đây như đã giải thích ở trên, chế độ xem của s là đơn vị cha mẹ duy nhất, để tạo nó cho cả phụ huynh và trẻ em, chúng ta cần phải bỏ qua

var c = (Vòng tròn) s;

Ví dụ thực tế của Downcasting là lớp nút của WPF.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.