downcast และ upcast


89

ฉันยังใหม่กับC # (และOOP ) เมื่อฉันมีรหัสดังต่อไปนี้:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

คำถามที่ 1 : หากฉันมีรหัสอื่นที่ทำสิ่งนี้:

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

นี่EmployeeคือManagerแต่เมื่อฉันโยนมันแบบEmployeeนั้นหมายความว่าฉันกำลังอัปเดตหรือไม่?

คำถาม 2 :

เมื่อฉันมีEmployeeคลาสออบเจ็กต์หลายชิ้นและมีบางคลาส แต่ไม่ใช่ทั้งหมดManagerฉันจะดาวน์แคสต์ได้อย่างไร?


6
การอัปเดตสามารถทำได้โดยไม่ต้องแคสต์อย่างชัดเจน ดังนั้นEmployee emp= mgr;ควรพอเพียง
จูบรักแร้ของฉัน

คำตอบ:


95
  1. ถูกต้อง. เมื่อคุณทำเช่นนั้นคุณจะหล่อมันลงในemployeeวัตถุนั่นหมายความว่าคุณไม่สามารถเข้าถึงผู้จัดการเฉพาะ

  2. Downcasting คือการที่คุณใช้คลาสพื้นฐานแล้วลองเปลี่ยนเป็นคลาสที่เฉพาะเจาะจงมากขึ้น สิ่งนี้สามารถทำได้โดยใช้ is และการร่ายที่ชัดเจนเช่นนี้:

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

หรือด้วยตัวasดำเนินการดังนี้:

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

หากมีสิ่งใดไม่ชัดเจนเรายินดีที่จะแก้ไข!


ฉันต้องการตัวอย่างเพื่อทราบว่า Downcasting คืออะไร?
user184805

4
หลีกเลี่ยงการกำหนดคำศัพท์ใหม่ที่เป็นที่ยอมรับ: "การชกมวย" ในบริบทของ OOP และ C # หมายถึงสิ่งที่ค่อนข้างแตกต่าง (= การรวมออบเจ็กต์ประเภทค่าไว้ในข้อมูลอ้างอิง) นอกจากนี้ตัวอย่างของคุณสามารถ (และควร) ใช้ตัวasดำเนินการแทนisตามด้วยการแคสต์
Konrad Rudolph

2
ฉันได้รับการแก้ไขในจุดแรกและฉันเปลี่ยนคำตอบครึ่งหลังเพื่อแสดงทั้งสองวิธีในการทำ
RCIX

3
คำสั่งแรกของคุณ ("... การส่ง [ตัวอย่างของคลาสผู้จัดการ] ไปยังออบเจ็กต์" พนักงาน "[.. ] หมายความว่าคุณไม่สามารถเข้าถึงสิ่งที่ผู้จัดการเฉพาะเจาะจง") ไม่ถูกต้องอย่างสมบูรณ์ ในตัวอย่างของ OP ถ้าพนักงานมีสมาชิกเสมือนที่ถูกแทนที่ใน Manager CLR จะเรียกการใช้งาน Manager แม้ว่าจะมีการแคสต์ก็ตาม จากบทความ MSDN เกี่ยวกับความหลากหลายใน C #: "เมื่อคลาสที่ได้รับมาแทนที่สมาชิกเสมือนสมาชิกนั้นจะถูกเรียกแม้ว่าอินสแตนซ์ของคลาสนั้นจะถูกเข้าถึงเป็นอินสแตนซ์ของคลาสพื้นฐานก็ตาม" ตัวอย่างที่จัดทำโดย MSDN นั้นแทบจะเหมือนกัน
Antony

49

โดย(Employee)someInstanceทั่วไปแล้วการอัพคาสต์ (โดยใช้) เป็นเรื่องง่ายเนื่องจากคอมไพเลอร์สามารถบอกคุณได้ในเวลาคอมไพล์หากประเภทนั้นมาจากประเภทอื่น

อย่างไรก็ตามการดาวน์คาสต์จะต้องทำในขณะทำงานโดยทั่วไปเนื่องจากคอมไพเลอร์อาจไม่ทราบเสมอไปว่าอินสแตนซ์ที่เป็นปัญหานั้นเป็นประเภทที่กำหนดหรือไม่ C # ให้สองผู้ประกอบการสำหรับการนี้ - เป็นที่จะบอกคุณถ้างานเศร้าใจและกลับ / เท็จจริง และตามที่พยายามทำการร่ายและส่งคืนประเภทที่ถูกต้องหากเป็นไปได้หรือเป็นโมฆะหากไม่

วิธีทดสอบว่าพนักงานเป็นผู้จัดการหรือไม่:

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

คุณยังสามารถใช้สิ่งนี้

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คือการดำเนินการที่สร้างการอ้างอิงคลาสพื้นฐานจากการอ้างอิงคลาสย่อย (subclass -> superclass) (เช่นผู้จัดการ -> พนักงาน)
  • Downcastingคือการดำเนินการที่สร้างการอ้างอิงคลาสย่อยจากการอ้างอิงคลาสพื้นฐาน (superclass -> subclass) (เช่นพนักงาน -> ผู้จัดการ)

ในกรณีของคุณ

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

คุณกำลังทำการอัปเดต

การอัปเดตจะประสบความสำเร็จเสมอซึ่งแตกต่างจากการดาวน์คาสต์ที่ต้องใช้การแคสต์อย่างชัดเจนเนื่องจากอาจล้มเหลวในขณะรันไทม์ ( InvalidCastException )

C # เสนอตัวดำเนินการสองตัวเพื่อหลีกเลี่ยงข้อยกเว้นนี้ที่จะเกิดขึ้น:

เริ่มจาก:

Employee e = new Employee();

อันดับแรก:

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

ประการที่สอง:

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

คำเตือน : เมื่อคุณทำการ upcast คุณสามารถเข้าถึงเมธอด superclass เท่านั้นคุณสมบัติและอื่น ๆ ...


6

ในกรณีที่คุณต้องการตรวจสอบอ็อบเจ็กต์ Employee แต่ละตัวว่าเป็นอ็อบเจ็กต์ Manager หรือไม่ให้ใช้เมธอด 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

คำตอบ 1: ใช่มันเรียกว่า upcasting แต่วิธีที่คุณทำไม่ใช่วิธีที่ทันสมัย Upcasting สามารถทำได้โดยปริยายคุณไม่จำเป็นต้องแปลงใด ๆ ดังนั้นแค่เขียนEmployee emp = mgr; ก็เพียงพอสำหรับการอัปเดต

คำตอบ 2: ถ้าคุณสร้าง object ของคลาส Manager เราสามารถพูดได้ว่า manager เป็นพนักงาน เนื่องจากผู้จัดการชั้นเรียน: พนักงานแสดงให้เห็นถึงความสัมพันธ์แบบ Is-Aระหว่างคลาสพนักงานและคลาสผู้จัดการ ดังนั้นเราสามารถพูดได้ว่าผู้จัดการทุกคนคือพนักงาน

แต่ถ้าเราสร้าง object ของคลาส Employee เราก็ไม่สามารถพูดได้ว่าพนักงานคนนี้เป็น manager เพราะคลาส Employeeคือคลาสที่ไม่ได้สืบทอดคลาสอื่น ดังนั้นคุณจึงไม่สามารถดาวน์คาสต์ได้โดยตรงว่าคลาสของพนักงานอ็อบเจ็กต์คลาสผู้จัดการ

ดังนั้นคำตอบคือถ้าคุณต้องการดาวน์คาสต์จากอ็อบเจ็กต์คลาสของพนักงานไปยังอ็อบเจ็กต์คลาสผู้จัดการก่อนอื่นคุณต้องมีอ็อบเจ็กต์ของคลาสผู้จัดการก่อนจากนั้นคุณสามารถอัปคาสต์ได้จากนั้นคุณสามารถดาวน์แคสต์ได้


-1

Upcasting และ Downcasting:

Upcasting: การแคสต์จากคลาส Derived-Class ไปยัง Base Class Downcasting: การแคสต์จากคลาสพื้นฐานไปยังคลาสที่ได้รับ

มาทำความเข้าใจเช่นเดียวกับตัวอย่าง:

พิจารณาสองคลาส Shape as My parent class และ Circle as a Derived class ซึ่งกำหนดไว้ดังนี้:

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

การอัปโหลด:

รูปร่าง s = รูปร่างใหม่ ();

วงกลม c = s;

ทั้ง c และ s อ้างถึงตำแหน่งหน่วยความจำเดียวกัน แต่ทั้งสองมีมุมมองที่แตกต่างกันคือการใช้การอ้างอิง "c" คุณสามารถเข้าถึงคุณสมบัติทั้งหมดของคลาสฐานและคลาสที่ได้รับเช่นกัน แต่การใช้การอ้างอิง "s" คุณสามารถเข้าถึงคุณสมบัติได้ ของคลาสหลักเท่านั้น

ตัวอย่างที่ใช้ได้จริงของ upcasting คือคลาส Stream ซึ่งเป็นคลาสพื้นฐานของโปรแกรมอ่านสตรีมทุกประเภทของ. net framework:

โปรแกรมอ่าน StreamReader = StreamReader ใหม่ (FileStreamReader ใหม่ ());

ที่นี่ FileStreamReader () ถูกอัปเดตเป็น streadm reder

Downcasting:

รูปร่าง s = วงกลมใหม่ (); ที่นี่ตามที่อธิบายไว้ข้างต้นมุมมองของ s เป็นผู้ปกครองเพียงคนเดียวเพื่อที่จะทำให้ทั้งผู้ปกครองและเด็กเราจำเป็นต้องปรับลดลง

var c = (วงกลม) s;

ตัวอย่างที่ใช้ได้จริงของ Downcasting คือระดับปุ่มของ WPF

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.