2009-07-21 4 views
8

Câu hỏi này thực sự là kinda vô nghĩa, nhưng tôi chỉ tò mò:Tại sao việc khai báo lớp C# này lại biên dịch?

này:

public sealed class MyClass 
{ 
    protected void MyMethod(){} 
} 

biên dịch, nhưng đưa ra một cảnh báo

khi này:

public sealed class MyClass 
{ 
    public virtual void MyMethod(){} 
} 

doesn không biên dịch. Chỉ vì tò mò tuyệt đối, có lý do cho việc này không?

+9

Tôi muốn trả lời, nhưng vì một lý do nào đó tôi nghĩ JS sẽ có câu trả lời hay hơn. Hmm. –

+2

Dường như JS đang ưu tiên SO tại THREAD_PRIORITY_BELOW_NORMAL - mọi người nhanh chóng nhận được câu trả lời của bạn trong khi bạn vẫn có thể! – cfeduke

+0

+1 câu hỏi hay, tôi thậm chí không bao giờ chạy vào nguyên nhân này tôi thậm chí không bao giờ nghĩ đến việc này ... bởi vì nó không có ý nghĩa gì cả! –

Trả lời

4

Lý do duy nhất tôi có thể nghĩ là đôi khi bạn cần viết các phương thức được bảo vệ để ghi đè lên các phương thức được bảo vệ khác. Ngôn ngữ thể đã được thiết kế để cho phép điều này:

protected override void Foo() 

nhưng không này

protected void Foo() 

nhưng điều đó có thể đã bị coi là một ít khó khăn để làm theo - đó là vắng mặt của override mà làm cho nó vô dụng, trong khi trong trường hợp của

public virtual void Foo() 

nó là hiện diện của virtual đó là vô ích. Sự hiện diện của một cái gì đó "sai" có lẽ dễ hiểu hơn là sự vắng mặt của một cái gì đó hữu ích.

Trong trường hợp này, là ảo cũng có thể có tác động hiệu suất, trong khi thực hiện một cái gì đó được bảo vệ thay vì tư nhân có lẽ không - vì vậy nó là một chút nghiêm trọng hơn.

Đây chỉ là phỏng đoán mặc dù thực sự - nếu chúng tôi thực sự may mắn, Eric Lippert sẽ đưa ra một câu trả lời dứt khoát hơn. Anh ấy là một trong những bạn muốn, không phải là tôi :)

câu trả lời hay nhất: đối xử với cảnh báo là lỗi và chúng tương đương anyway;)

+0

Ooh, tốt, tôi không nghĩ đến trường hợp lớp kín trong câu hỏi được thừa hưởng từ một cơ sở và ghi đè lên một thành viên được bảo vệ. Đó có thể là lý do. Tôi thực sự đã gửi email cho Eric tối qua, và anh ấy đã trả lời nói rằng anh ta sẽ nhìn vào nó và lấy lại cho tôi Tôi sẽ giữ cho câu hỏi này mở cho đến khi anh ta làm ơn, cám ơn Jon – BFree

+1

Hey, tôi cũng đoán vậy, các bạn. một phương pháp ảo vào một loại niêm phong một lỗi đã được thực hiện vào ngày 18 tháng 10 năm 1999, nhưng không đưa ra bất kỳ biện minh nào cho quyết định đó. đoán tốt nhất: điều này có lẽ chỉ đơn giản là một sự giám sát trong phiên bản đầu tiên, và sau đó nó đã trở thành một sự thay đổi đột phá để sửa chữa nó –

+2

@Eric: Không quan tâm, đâu là điều này trong spec? Nó không xuất hiện trong phần giới thiệu của 10.6 wh ich liệt kê các quy tắc để kết hợp các công cụ sửa đổi hợp lệ. Tôi nghĩ rằng tôi muốn tìm quy tắc và sau đó xem nếu nó được đề cập trong một trong các thông số kỹ thuật chú thích ... và bây giờ tôi không thể tìm thấy quy tắc. Tôi cũng không thể thấy nó trong 10.6.3. –

12

virtual được sử dụng để khai báo phương thức/thuộc tính "ghi đè có thể".

sealed được sử dụng để khai báo rằng lớp học không thể được kế thừa từ đó.

Vì vậy, một phương pháp ảo trong một lớp niêm phong không bao giờ có thể được ghi đè, vì lớp học không bao giờ có thể được kế thừa từ đó. Nó chỉ không có ý nghĩa.

protected ảnh hưởng đến quyền truy cập vào một thành viên, nó không tuyên bố "ghi đè có thể" là ảo (mặc dù nó thường được sử dụng theo cách đó) và không phù hợp.

+0

Vâng, tôi hiểu điều đó. Lưu ý tôi đã không hỏi "tại sao không biên dịch này" thay vì tôi hỏi tại sao điều này biên dịch. Cùng một cách ảo không có ý nghĩa trong một lớp kín, bảo vệ không nhìn thấy những gì tôi đang nói? – BFree

+0

Tôi nghĩ * OP nhận ra rằng 'niêm phong' không có ý nghĩa đặc biệt với' virtual' hoặc với 'protected'. Anh ấy tự hỏi tại sao một mục "không có ý nghĩa" được cho phép, trong khi một mục khác thì không. –

+0

@ 280Z28 Tôi đồng ý ... Chúng tôi cần Skeeter giải thích điều này cho chúng tôi. –

4

Tôi không thể thấy lý do chính đáng cho việc này. MyMethod được bảo vệ có thể được gọi từ MyClass, nhưng sẽ không bao giờ được gọi từ một lớp dẫn xuất (vì MyClass được niêm phong). Phiên bản ảo cũng được phép được gọi trực tiếp từ MyClass, nhưng nó là bất hợp pháp đối với phương thức để ghi đè vì bạn không thể lấy được một lớp từ MyClass ...

2

Một lớp niêm phong có thể có các thành viên được bảo vệ thông qua thừa kế . Khi một phương pháp là một phần của một lớp học, nó không quan trọng như thế nào phương pháp đó đã có.

Trong trường hợp đầu tiên, với phương pháp được bảo vệ trên lớp được niêm phong, nó giống như lớp niêm phong kế thừa một phương thức được bảo vệ. Vì vậy, nó biên dịch.

Hết sức tò mò, cảnh báo được đưa ra là gì?

+0

Cảnh báo là: "cảnh báo CS0628: 'SimpleTestApp.Class1.foo()': thành viên được bảo vệ mới được khai báo trong lớp được niêm phong." –

1

Một lớp được niêm phong không thể được phân loại, do đó, ảo không phải là một tùy chọn. Vì vậy, lỗi.

Điều này đầu tiên hơi ngớ ngẩn nhưng hợp lệ, do đó cảnh báo.

2

Lỗi này là:

CS0549: 'chức năng' là một thành viên ảo mới trong lớp niêm phong 'lớp'.

Trước hết, mặc dù thực tế rằng nó không thực sự có ý nghĩa với bao gồm mới protected hoặc virtual thành viên trong một lớp học sealed, các CLI¹ không cho phép nó. CLI cũng cho phép gọi các thành viên của một lớp kín bằng cách sử dụng lệnh callvirt IL, mặc dù trình biên dịch có thể tự do thay thế nó bằng lệnh call.

Hiện tại, tôi không thể tìm thấy bất kỳ điều gì trong ECMA-334 (Đặc tả ngôn ngữ C#) yêu cầu trình biên dịch phát ra lỗi ở trên. Có vẻ như việc triển khai của Microsoft đã thêm lỗi chỉ vì không có ý nghĩa gì khi đưa các thành viên ảo mới vào một lớp được niêm phong.

¹The CLI là một máy ảo và trình biên dịch C# phát ra mã byte chạy trên đó. Hầu như bất kỳ khái niệm nào là bất hợp pháp trong CLI cũng là bất hợp pháp trong C# vì lý do đó - nhưng đây là trường hợp C# thực hiện thêm một chút (không phải là vấn đề).

Chỉnh sửa: Dường như các bài đăng được đánh dấu là giải thích lý do tại sao số không có ý nghĩa để viết mã như vậy trong OP. Nhưng liên quan đến những gì quy tắc đã làm cho nó một lỗi biên dịch họ xuất hiện là sai.

0

Tôi đoán trình biên dịch thực hiện một số tối ưu hóa với các lớp được niêm phong không thể nếu bạn có phương thức ảo được khai báo - "không có vtable" có vẻ là một ứng cử viên có khả năng.

Đó chỉ là phỏng đoán.

0

Như kín When applied to a class, the sealed modifier prevents other classes from inheriting from it.

đây tôi đang cố gắng để giải thích cho bạn từng cái một :

public sealed class MyClass 
{ 
    protected void MyMethod(){} 
} 

nó mang lại cho bạn cảnh báo vì thực tế nó làm cho không có ý nghĩa bởi vì sau khi tuyên bố một lớp học như kín bạn không thể thừa hưởng nó và như phương pháp của bạn là protected nên bạn không thể truy cập nó bên ngoài lớp học sử dụng nó objec t (và cũng lưu ý rằng bạn không thể tạo ra một lớp con của điều này để bạn không thể sử dụng phương pháp này bằng cách lừa cũng). Thực tế nó không có ý nghĩa để làm cho nó protected để trình biên dịch cung cấp cho bạn một cảnh báo nhưng nếu bạn làm cho nó như là public hoặc internal sau đó nó sẽ không cung cấp cho bạn lỗi vì nó hữu ích trong trường hợp đó.

nay là thứ hai:

public sealed class MyClass 
{ 
    public virtual void MyMethod(){} 
} 

như bạn kín bạn lớp và bây giờ bạn đang làm phương pháp của bạn là ảo nên gián tiếp bạn đang đưa ra một lời đề nghị với ai đó để ghi đè lên nó và có thể là duy nhất có thể bằng cách thừa kế và ở đây có vấn đề. Do đó bạn lớp được niêm phong để bạn không thể thực hiện kế thừa với lớp này.so đó là lý do tại sao với virtual nó cho lỗi.

tôi hy vọng nó sẽ giúp bạn hiểu.

để tham khảo http://msdn.microsoft.com/en-us/library/88c54tsw.aspx

0

Khai báo một thành viên bảo vệ mới bao hàm một ý định chia sẻ rằng thành viên với các lớp hậu duệ. Một lớp niêm phong không thể có hậu duệ, vì vậy tuyên bố một thành viên được bảo vệ mới là một chút của một oxymoron, giống như khai báo một phương thức ảo mới trong một lớp được niêm phong. Đối với lý do tại sao ảo tạo ra lỗi khi được bảo vệ chỉ tạo cảnh báo, tôi chỉ có thể suy đoán rằng có lẽ nó phải làm với thực tế là các phương thức ảo mới yêu cầu trình biên dịch xây dựng cấu trúc dữ liệu cho loại (vtable), trong khi các thành viên mới được bảo vệ chỉ có một bộ cờ truy cập - không có cấu trúc dữ liệu mới. Nếu trình biên dịch bị cấm tạo ra một vtable cho một lớp kín, nó sẽ làm gì nếu nó gặp một phương thức ảo mới? Không biên dịch. Một phương pháp bảo vệ mới trong một lớp kín là vô nghĩa nhưng không yêu cầu trình biên dịch mạo hiểm vào lãnh thổ bị cấm.