2009-04-16 67 views
6

Mã sau có nên đưa ra cảnh báo không?Tại sao phương pháp tĩnh của tôi ẩn phương pháp thể hiện của tôi?

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { public static void Do() { /*...*/ } /*...*/ } 

Nó cung cấp cho:

"Cảnh báo CS0108:.. 'Bar.Do()' ẩn thành viên được thừa hưởng 'Foo.Do()' Sử dụng các từ khóa mới nếu trốn được dự định"

Nếu tôi thực hiện một sự thay đổi để mã:

class Foo { public static void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { public void Do() { /*...*/ } /*...*/ } 

Tôi nhận được cảnh báo tương tự.

Nếu tôi thực hiện thay đổi sau, cảnh báo sẽ biến mất.

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { new public static void Do() { /*...*/ } /*...*/ } 

Hãy để tôi thực hiện thay đổi thêm:

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { 
    new public static void Do() 
    { new Bar().Do();/*...*/ } /*...*/ 
} 

này không biên dịch:

"Lỗi CS0176: Thành viên 'Bar.Do()' không thể được truy cập với một thể hiện tham chiếu; thay vào đó, hãy hội đủ điều kiện với tên loại. "

Vì vậy, tôi mất quyền truy cập vào phương thức kế thừa của mình thông qua tham chiếu mẫu từ phương pháp tĩnh!

Điều gì sẽ là logic đằng sau nó? Hay tôi đã đánh máy ở đâu đó?

Tôi đã xem xét điều này khi tôi cố gắng xác định phương pháp tĩnh 'Hiển thị' cho biểu mẫu của tôi bắt nguồn từ 'Biểu mẫu'.

Trả lời

5

Bạn nghĩ lỗi ở đâu? Thực tế là có một cảnh báo là hoàn toàn đúng. Từ spec C# 3.0, phần 10.3.4:

Một đẳng cấp thành viên tuyên bố là phép khai báo một thành viên có cùng tên hoặc chữ ký như một thừa hưởng thành viên.Khi điều này xảy ra, thành viên lớp học bắt buộc được cho là ẩn thành viên lớp cơ sở . Ẩn một thành viên được thừa kế không được coi là lỗi, nhưng nó làm cho trình biên dịch đưa ra cảnh báo . Để ngăn chặn cảnh báo, khai báo của lớp dẫn xuất thành viên có thể bao gồm công cụ sửa đổi mới thành cho biết thành viên có nguồn gốc là nhằm ẩn thành viên cơ sở.

Thực tế là phương pháp gọi của bạn bị lỗi là tinh vi hơn, nhưng đó là về cơ bản bởi vì các thuật toán tìm kiếm thành viên chọn phương pháp tĩnh, và sau đó phần này của phần 7.5.5.1 được sử dụng:

xác nhận cuối cùng của các lựa chọn tốt nhất phương pháp được thực hiện:

phương pháp này được xác nhận trong bối cảnh các nhóm phương pháp : Nếu phương pháp tốt nhất là một phương pháp tĩnh, nhóm phương pháp phải có là kết quả của một tên đơn giản hoặc truy cập thành viên thông qua một loại. Nếu phương pháp tốt nhất là phương pháp thể hiện, nhóm phương pháp phải có kết quả từ tên đơn giản , quyền truy cập thành viên thông qua biến số hoặc giá trị hoặc quyền truy cập cơ sở. Nếu không có yêu cầu nào trong số các yêu cầu này là đúng, xảy ra lỗi biên dịch.

+0

Xin chào Jon, +1 để trả lời. Tôi nghĩ rằng, từ góc độ người dùng ngôn ngữ, lỗi là cách chọn phương pháp tốt nhất để gọi :-). Với tôi, "new Bar(). Do()" cho biết rõ ràng phương thức nào đang được gọi lúc biên dịch và không cần phải tạo ra lỗi! – isntn

+1

Tôi nghi ngờ cách thay thế là làm cho ngôn ngữ phức tạp hơn nhiều. Có những trường hợp khá thường xuyên có thể được cải thiện nếu ngôn ngữ thông minh hơn - nhưng sau đó sẽ khó hơn để "biết" ngôn ngữ tốt, và cũng để thực hiện chính xác nó trong trình biên dịch. Đó là tất cả sự cân bằng ... –

2

Không, điều đó có ý nghĩa hoàn hảo. Điều này hoạt động như mong đợi:

using System; 
using System.Collections.Generic; 

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { 
    new public static void Do() 
    { ((Foo)new Bar()).Do();/*...*/ } /*...*/ 
} 

Đó là do trình biên dịch giả định rằng bạn có loại Bar và sau đó tìm thành viên tĩnh. Bằng cách chuyển nó sang Foo (mà đi kèm với btw miễn phí.) Bạn làm cho nó nhìn vào siêu dữ liệu cho Foo() và tất cả là tốt.

+0

Khi tôi nói. "Bar mới() Do();". Tôi chắc chắn gọi phương thức cá thể "Do", có sẵn trong Bar qua Foo. Vì vậy, tại sao chúng ta phải gõ cast? – isntn

+1

Bởi vì trình biên dịch không nhìn vào thể hiện, nhưng ở loại siêu dữ liệu. Và ở đây nó chỉ tìm thấy một phương thức có chữ ký chính xác (tên và danh sách đối số trống) và đó là phương thức tĩnh. – Lucero

+0

Hãy suy nghĩ về nó trong điều khoản của bảng fuction ảo; ánh xạ Bar :: Do() ẩn ánh xạ của Foo: Do ​​(). –

2

Hãy thử điều này:

 new public static void Do() 
     { 
      ((Foo)new Bar()).Do(); 
     } 
0

Trong mẫu mã cuối cùng của bạn, từ khóa mới trên tờ khai của Bar.Do() có nghĩa là bạn có ý định giấu Foo.Do().

0

Ngoài sự tò mò, tại sao bạn muốn làm điều này? Nó có vẻ như bạn có thể đi về giải pháp của bạn một cách sai lầm.

Đoạn mã trên dường như hoạt động bình thường và thông báo trình biên dịch cho bạn biết vấn đề là gì.

+0

Xin chào Josh, tôi không "muốn" làm điều đó. Nó chỉ là tôi đi qua điều này, và muốn hiểu hành vi này được lựa chọn bởi các nhà thiết kế C#. "new Bar(). Do()" nói rõ ràng rằng nó là phương thức instance được gọi. Vì vậy, tại sao C# được thiết kế để làm cho điều này rõ ràng hơn? một chút câu hỏi giáo dục. – isntn

+0

Tôi hiểu. Vâng, trong trường hợp đó, bạn phải nhận ra rằng trong Bar, có phương thức * no * instance có tên Do(), chỉ là một phương thức tĩnh. Bằng cách cho nó cùng một tên, bạn đã chặn kế thừa. Vì vậy, không có, nó không phải là rõ ràng rằng phương pháp dụ được gọi là, với tôi hoặc trình biên dịch = p – JoshJordan

+0

Tôi nghĩ rằng, có phương pháp dụ trong Bar có nguồn gốc từ Foo. – isntn

1

bạn sẽ có thể gọi nó bằng cách làm gọi base.Do() chứ không phải là Bar() Do()

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