2012-04-16 45 views
8

Giả sử tôi có hai lớp:Cast cơ sở dụ để lớp có nguồn gốc (nhìn xuống) trong C#

class Employee 

class AdvancedEmployee:Employee 

Tôi biết một cái gì đó như thế này sẽ không hoạt động, như tôi không thể downcast trên C#:

var employee = new Employee(); 
var advanced = employee as AdvancedEmployee; 

Câu hỏi của tôi là: Làm thế nào để thực hiện downcast một cách hiệu quả? Thực ra tôi có một hàm tạo trên AdvancedEmployee lấy một Employee làm tham số và sử dụng nó để tiêm các giá trị của nó, về cơ bản tạo một bản sao.


Cập nhật

Để giải quyết các dữ liệu đó sẽ được nhân đôi tôi đã thay đổi cách tiếp cận một chút và bây giờ AdvancedEmployee CHỨA một nhân viên chứ không phải là một chính nó. Ví dụ:

class Employee; 

class AdvancedEmployee 
{ 
    private employee 

    public AdvancedEmployee(Employee employee){ 

    this.employee = employee 

    }   

} 
+2

Làm cho cả hai phù hợp với giao diện, IEmployee? – SpaceBison

+0

Tôi không thể sửa đổi Nhân viên. –

+0

@IsraelLot, bạn chắc chắn có thể downcast trong C#. Tôi nghi ngờ bạn chỉ thiếu cú ​​pháp: 'AdvancedEmployee advanced = (AdvancedEmployee) nhân viên;' Tất nhiên điều này sẽ cung cấp cho một lỗi thời gian chạy nếu đối tượng tham chiếu không phải là trong thực tế một thể hiện của AdvancedEmployee. – Ben

Trả lời

3

Nó không thể là một diễn viên , nó thực sự là một chuyển đổi giữa các loại khác nhau.

Tôi sẽ thêm hàm ctor hoặc hàm thành viên tĩnh như AdvancedEmployee FromBase(Employee e), để xây dựng loại có nguồn gốc từ loại cơ sở nhất định.

+0

@downvoter: quan tâm giải thích? – Tigran

1

as trong C# kiểm tra loại thời gian chạy . Tức là, nếu đối tượng đang được thử nghiệm thực sự không phải là AdvancedEmployee, bạn sẽ không biến nó thành ma thuật Employee thành AdvancedEmployee. Vì vậy, nếu bạn cần một AdvancedEmployee, bạn cần phải xây dựng nó cho mình bằng cách nào đó.

Có nhiều cách tiếp cận khác nhau tùy thuộc vào những gì bạn sẽ đạt được. Có lẽ bạn có thể làm với một nhà xây dựng AdvancedEmployee(Employee proto), mà sẽ sao chép các giá trị cần thiết từ proto? Hoặc có thể bạn cần bọc Employee hiện tại với AdvancedEmployee.

Lưu ý rằng bạn có thể cần phải để mã lưu trữ nhân viên cũ thay thế bằng số mới AdvancedEmployee mới tạo của bạn.

Một cách để đi (với một số hương vị Java) có thể là để tạo ra một nhà máy Employee, mà sẽ tạo ra một AdvancedEmployee nếu cần thiết. Sau đó, bạn cần phải làm cho tất cả các mã sử dụng nhà máy thay vì tạo ra một Employee với new. Kịch bản này tuy nhiên sẽ không giúp đỡ nếu bạn cần thay đổi kiểu thời gian chạy của bạn.

+0

Đó là những gì tôi đang làm ngay bây giờ. Tôi đã tự hỏi nếu có một cách ưa thích. –

+2

Không thực sự. Có một ngôn ngữ OO khác mà bạn có thể thay đổi kiểu _runtime_ của một đối tượng đang bay - nhưng không phải trong C#/Java/C++. trong C#, bạn chỉ có thể tạo đối tượng _new_. – Vlad

+0

@downvoter: quan tâm giải thích? – Vlad

2

Tạo đối tượng mới là cách dễ đọc nhất và rõ ràng nhất. Bạn cũng có thể định nghĩa toán tử chuyển đổi loại rõ ràng hoặc ngầm định trong lớp Employee của bạn.

public static explicit operator AdvancedEmployee(Employee e) 
{ 
    return new AdvancedEmployee(e); 
} 

Và sau đó sử dụng nó như thế này:

var e = new Employee(); 
var ae = (AdvancedEmployee) e; 
+0

Vì OP không thể sửa đổi 'Employee', anh ta cũng không thể xác định các toán tử chuyển đổi loại rõ ràng hoặc ngầm định bên trong nó. – comecme

4

Tạo một giao diện.Và kể từ khi bạn không thể sửa đổi nhân viên, tạo ra một adapter mà bạn sở hữu:

class EmployeeAdapter : IEmployee 
{ 
    private Employee emp; 
    public EmployeeAdapter(Employee emp) { this.emp = emp; } 
    public int SomeMethodInEmployee() { return emp.SomeMethodInEmployee(); } 
} 

class AdvancedEmployee : IEmployee { } 
+0

@downvoter: quan tâm giải thích? –

+0

Downvote là lỗi của tôi. Tôi đã đọc sai câu hỏi. Thật không may một số sự không hài lòng có nghĩa là tôi không thể hoàn nguyên phiếu bầu của mình bây giờ tôi nhận ra mình đã nhầm lẫn. – Ben

+1

Tắt nếu bạn chỉnh sửa bài đăng (thậm chí thêm một dấu cách), sau đó bạn có thể hoàn nguyên phiếu bầu của mình. – Ben

2

Đây là một cách mà tôi đã xử lý nó trong quá khứ mà tôi nghĩ là kinda cool ... nếu tất cả các yếu tố dữ liệu trong nhân viên và AdvancedEmployee là các thuộc tính, sau đó bạn có thể sử dụng sự phản chiếu để sao chép các giá trị dữ liệu từ lớp cơ sở vào lớp dẫn xuất. Sau đó, bạn có thể làm việc với lớp dẫn xuất như thể ban đầu anh ta đã gõ theo cách đó mà không phải đóng gói lớp cơ sở.

public class Employee 
{ 
    public int ID { get; set; } 
    public string Foo { get; set; } 

    public void SomeMethod() { } 
} 

public class AdvancedEmployee : Employee 
{ 
    public string Bar { get; set; } 

    public void SomeAdvMethod() { } 
} 

Employee emp = new Employee() { ID = 5, Foo = "Hello" }; 

// To create a AdvancedEmployee from emp 
AdvancedEmployee advEmp = new AdvancedEmployee() { Bar = "A prop not in Emp that might need a value" } 
foreach (var p in typeof(Employee).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite)) 
    typeof(AdvancedEmployee).GetProperty(p.Name).SetValue(advEmp, p.GetValue(emp)); 
Các vấn đề liên quan