2011-09-02 70 views
6

Tôi có một tình huống mà tôi muốn ghi đè lên một phương thức của lớp cơ sở để thay đổi một chút kiểu trả về của phương thức. Bằng cách thay đổi một chút tôi có nghĩa là trả về một đối tượng được thừa kế từ đối tượng mà có thể đã được trả lại theo phương pháp trong các loại hình cơ sở ... trên thực tế, một mã số ít sẽ làm cho dễ dàng hơn này ...Phương pháp ghi đè để thay đổi kiểu trả về

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new ParentClass(); 
     Console.WriteLine("Parent says: " + obj.ShowYourHand()); 

     var obj2 = new ChildClass(); 
     Console.WriteLine("Child says: " + obj2.ShowYourHand()); 

     Console.ReadLine(); 
    } 
} 

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = GetExternalObject(); 
     return obj.ToString(); 
    } 
    protected virtual ExternalObject GetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    protected virtual new ExternalObjectStub GetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 

public class ExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObject"; 
    } 
} 

public class ExternalObjectStub : ExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObjectStub"; 
    } 
} 

Vấn đề tôi có là trường hợp của obj2 không gọi nó là phiên bản của GetExternalObject() nhưng thay vì sử dụng thực hiện của cha mẹ nó.

Tôi nghĩ rằng nó đang làm như vậy bởi vì trong mã

var obj = GetExternalObject(); 

loại obj dự kiến ​​sẽ được ExternalObject trong lớp cha mẹ. Tuy nhiên, tôi hiểu rằng C# không thể phân biệt giữa các phương thức dựa trên kiểu trả về.

Tôi biết có các giải pháp khác cho vấn đề như xác định IExternalObject để không bị quá tải về điều đó. Tất cả những gì tôi muốn biết là suy nghĩ là gì ngăn cản các lớp con GetExternalObject khỏi bị gọi ngay cả bởi chính lớp con?

Hoặc tôi có đang làm điều gì đó hoàn toàn không? :-)

+0

tương tự câu hỏi: [C#: kiểu trả về Overriding] (http://stackoverflow.com/questions/1048884/c-overriding-return-types) –

+0

có thể trùng lặp của [C#: kiểu trả về Overriding] (https : //stackoverflow.com/questions/1048884/c-overriding-return-types) –

Trả lời

7

Hoặc tôi có đang làm điều gì đó hoàn toàn không? :-)

Có, bạn đang có. Bạn không thể thay đổi kiểu trả về của một phương thức bằng cách ghi đè nó. Tôi không hiểu nó trong mẫu của bạn anyway. Chỉ cần để nguyên loại trả lại và trả lại ExternalObjectStub mới. Điều này hoạt động, bởi vì ExternalObjectStub có nguồn gốc từ ExternalObject.

Thay đổi kiểu trả về bằng cách ẩn thành viên cơ sở với new như bạn làm, thường là một ý tưởng rất tồi, vì nó dẫn đến một lớp không thể được sử dụng theo cách đa hình. Đây là chính xác những gì bạn đang gặp phải ở đây: Nếu loại biến chứa tham chiếu là loại ParentClass, nó gọi phương thức trong ParentClass, ngay cả khi cá thể thực sự thuộc loại ChildClass, bởi vì ChildClass không cung cấp việc triển khai quá mức GetExternalObject.

4

Đa hình như bạn đang sử dụng, không chính xác. Bạn cần tạo một phương thức mới trong lớp con của bạn để ẩn việc thực thi lớp cơ sở, với kiểu trả về mới. Bạn không thể sử dụng các phương thức ảo để quá tải một phương thức như bạn đang làm.

Phương pháp ảo được sử dụng để tạo một cách khác nhau thực hiện của một phương thức trong lớp con, không phải "quá tải" như bạn đang cố gắng thực hiện.

Quá tải các phương thức được thực hiện bằng cách thay đổi các tham số, không phải kiểu trả về.

Vì vậy, hãy ẩn phương thức gốc, trong lớp con hoặc tạo phương thức bằng tên khác. Sử dụng ảo cho việc này sẽ không hoạt động.

0

Nếu bạn muốn quay trở lại ExternalObjectStub trong lớp con ExternalObjectStub này nên xuất phát từ ExternalObject lớp

2

Bạn nên có các lớp học của bạn trở lại một giao diện, với mỗi lớp (ParentClassChildClass) trở về một thể hiện của giao diện.Bạn cũng nên ghi đè phương thức GetExternalObject trong ChildClass để bảng v trỏ tới việc triển khai đúng.

Ngoài ra, mã của bạn bị lỗi đánh máy - phương pháp Main của bạn được tham chiếu obj hai lần khi bạn gọi ShowYourHand. Tôi cũng đã thay đổi điều đó, để tham chiếu objobj2. Dưới đây là cách bạn có thể thực hiện điều này với một giao diện (và sửa chữa các obj typo trong Main):

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new ParentClass(); 
     Console.WriteLine("Parent says: " + obj.ShowYourHand()); 

     var obj2 = new ChildClass(); 
     Console.WriteLine("Child says: " + obj2.ShowYourHand()); 

     Console.ReadLine(); 
    } 
} 

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = this.GetExternalObject(); 
     return obj.ToString(); 
    } 
    protected virtual IExternalObject GetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    protected override IExternalObject GetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 

public interface IExternalObject { } 

public class ExternalObject : IExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObject"; 
    } 
} 

public class ExternalObjectStub : IExternalObject 
{ 
    public override string ToString() 
    { 
     return "ExternalObjectStub"; 
    } 
} 
2

Tôi không nghĩ rằng bạn đang làm bất cứ điều gì ngớ ngẩn chút nào. Tôi thấy mình rất thường xuyên tìm cách để thực hiện cùng một mô hình này (Class Foo có một thuộc tính của kiểu Bar, Class FooSub: Foo sẽ có thể vạch trần thuộc tính đó như kiểu BarSub: Bar).

Một điều quan trọng cần hiểu về toán tử "mới" là nó chỉ ẩn thực hiện trên chính lớp con. Nếu lớp con được đưa trở lại lớp cơ sở, thì việc triển khai lớp cơ sở được sử dụng thay thế. Vì vậy, bạn sẽ muốn chắc chắn rằng bạn có một phương pháp "thực" để ghi đè để ngay cả khi điều này xảy ra, nó vẫn trả về kiểu thích hợp.

public class ParentClass 
{ 
    public string ShowYourHand() 
    { 
     var obj = GetExternalObject(); 
     return obj.ToString(); 
    } 

    protected ExternalObject GetExternalObject() 
    { 
     return this.RealGetExternalObject(); 
    } 

    protected virtual ExternalObject RealGetExternalObject() 
    { 
     return new ExternalObject(); 
    } 
} 

public class ChildClass : ParentClass 
{ 
    new protected ExternalObjectStub GetExternalObject() 
    { 
     return (ExternalObjectStub)this.RealGetExternalObject(); 
    } 

    protected override ExternalObject RealGetExternalObject() 
    { 
     return new ExternalObjectStub(); 
    } 
} 
Các vấn đề liên quan