2009-09-24 28 views
5

Chủ yếu là một nhà phát triển Java, tôi đã hơi ngạc nhiên bởi kết quả khi tôi một ngày vô tình sử dụng mới từ khóa thay vì ghi đè.Trường hợp sử dụng cho C# cho phép sử dụng mới trên một phương thức ảo là gì?

Có vẻ như từ khóa mới loại bỏ "độ ảo" của phương thức ở cấp đó trong cây thừa kế, để gọi phương thức trên thể hiện lớp con bị downcasted vào lớp cha, sẽ không giải quyết để triển khai phương thức trong lớp con.

Trường hợp sử dụng thực tế cho hành vi này là gì?

Làm rõ: Tôi hiểu việc sử dụng mới khi cha mẹ không phải là ảo. Tôi tò mò hơn tại sao trình biên dịch cho phép kết hợp mới và ảo.

Ví dụ sau minh họa sự khác biệt:

using System; 

public class FooBar 
{ 
    public virtual void AAA() 
    { 
     Console.WriteLine("FooBar:AAA"); 
    } 

    public virtual void CCC() 
    { 
     Console.WriteLine("FooBar:CCC"); 
    } 
} 

public class Bar : FooBar 
{ 
    public new void AAA() 
    { 
     Console.WriteLine("Bar:AAA"); 
    } 

    public override void CCC() 
    { 
     Console.WriteLine("Bar:CCC"); 
    } 
} 

public class TestClass 
{ 
    public static void Main() 
    { 
     FooBar a = new Bar(); 
     Bar b = new Bar(); 
     Console.WriteLine("Calling FooBar:AAA"); 
     a.AAA(); 
     Console.WriteLine("Calling FooBar:CCC"); 
     a.CCC(); 
     Console.WriteLine("Calling Bar:AAA"); 
     b.AAA(); 
     Console.WriteLine("Calling Bar:CCC"); 
     b.CCC(); 
     Console.ReadLine(); 
    } 
} 

này tạo ra kết quả như sau:

Calling FooBar:AAA 
FooBar:AAA 
Calling FooBar:CCC 
Bar:CCC 
Calling Bar:AAA 
Bar:AAA 
Calling Bar:CCC 
Bar:CCC 

Trả lời

15

Sử dụng trường hợp:

  • Hôm nay, bạn sử dụng một thư viện của bên thứ 3 và lấy được lớp Banana từ lớp Fruit.
  • Bạn triển khai phương thức có tên là Peel trong Banana. Không có Peel trong Fruit.
  • Ngày mai, bên thứ ba phát hành phiên bản mới của thư viện, bao gồm phương thức Fruit.Peel ảo
  • Bạn biên dịch lại mã của mình vào ngày mai. Bạn có muốn ghi đè Fruit.Peel không? Khá có thể không - nó có thể có một ý nghĩa hoàn toàn khác. Thay vào đó, bạn ẩn bằng Banana.Peel và tất cả các mã hiện tại hoạt động như hiện nay.

Nói cách khác, chủ yếu là tránh các vấn đề về phiên bản. Trong Java, bạn sẽ kết thúc ghi đè Fruit.peel mặc dù bạn không muốn, có thể dẫn đến các lỗi khó chẩn đoán.

+0

Ví dụ hay. Đó là một lựa chọn rất thuận tiện, nhưng tôi cho rằng nó có đủ cạm bẫy để đảm bảo một cảnh báo biên dịch. – PeterR

+0

Bạn sẽ nhận được cảnh báo biên dịch nếu bạn không * có 'mới' nhưng bạn đang ẩn một phương thức. Ý tưởng là nếu bạn * rõ ràng * thêm một công cụ sửa đổi, đó phải là một dấu hiệu cho thấy bạn thực sự có ý nghĩa đó :) –

2

Nói từ kinh nghiệm cá nhân, tôi chủ yếu nhìn thấy "mới" từ khóa được sử dụng trong trường hợp bản gốc phương thức gốc là không phải là được chỉ định là ảo, nhưng hành vi ghi đè được mong muốn. Áp dụng từ khóa "mới" "ẩn" phương thức gốc. Và, như bạn đã quan sát trong ví dụ mã, phương thức được viết bằng "mới" sẽ chỉ được thực hiện khi làm việc trực tiếp với loại đó. Nếu làm việc với kiểu cha, phương thức gốc của cha mẹ sẽ được gọi.

Để trả lời câu hỏi của bạn trực tiếp hơn - nó cung cấp phương tiện ghi đè phương thức khi phương thức gốc không được gắn nhãn ảo.

EDIT: Như một sang một bên, thêm từ khóa "mới" để ẩn một phương thức cha mẹ không được ghi đè tự nhiên không thực sự thay đổi bất kỳ thứ gì trong IL được tạo. Nhưng đó là một phương tiện để nêu một cách rõ ràng để các nhà phát triển "Này, bạn đang giấu một phương pháp cha mẹ ở đây, không trọng nó"

0

Giả thuyết ....

 

public class BaseCollection<T> 
{ 
    // void return - doesn't seem to care about notifying the 
    // client where the item was added; it has an IndexOf method 
    // the caller can use if wants that information 
    public virtual void Add(T item) 
    { 
    // adds the item somewhere, doesn't say where 
    } 

    public int IndexOf(T item) 
    { 
    // tells where the item is 
    } 
} 

public class List<T> : BaseCollection<T> 
{ 
    // here we have an Int32 return because our List is friendly 
    // and will tell the caller where the item was added 
    new public virtual int Add(T item) // <-- clearly not an override 
    { 
    base.Add(item); 
    return base.IndexOf(item); 
    } 
} 

Ở đây tôi sử dụng "mới" modifier vì một danh sách <T> tham khảo sẽ ẩn Add phương pháp từ BaseCollection <T>. Theo mặc định, ẩn các thành viên từ một cơ sở tạo ra một cảnh báo từ trình biên dịch (một lỗi nếu bạn có biên dịch thiết lập để thất bại trên các cảnh báo). Vì vậy, tôi về cơ bản nói với trình biên dịch ... "Vâng tôi biết tôi đã giấu phương pháp Thêm với khoảng trống, đó là chức năng mong muốn - chỉ cần đi với nó."

Các vấn đề liên quan