2011-02-07 17 views
302

tôi nhận thấy rằng với các thông số tùy chọn trong C# 4 nếu bạn chỉ định một tham số là tùy chọn trên một giao diện bạn KHÔNG phải làm tham số tùy chọn trên bất kỳ lớp thực hiện:Tại sao các tham số tùy chọn C# 4 được xác định trên giao diện không được thực thi trên lớp triển khai?

public interface MyInterface 
{ 
    void TestMethod(bool flag = false); 
} 

public class MyClass : MyInterface 
{ 
    public void TestMethod(bool flag) 
    { 
     Console.WriteLine(flag); 
    } 
} 

và do đó:

var obj = new MyClass();   
obj.TestMethod(); // compiler error 

var obj2 = new MyClass() as MyInterface; 
obj2.TestMethod(); // prints false 

Có ai biết tại sao các thông số tùy chọn được thiết kế để hoạt động theo cách này không? Một mặt tôi cho rằng khả năng ghi đè lên bất kỳ giá trị mặc định nào được chỉ định trên giao diện là hữu ích mặc dù tôi thực sự không chắc chắn liệu bạn có thể chỉ định giá trị mặc định trên giao diện hay không. phán quyết.

Mặt khác, ngắt kết nối này có nghĩa là bạn không thể luôn sử dụng lớp bê tông và giao diện thay thế lẫn nhau. Điều này tất nhiên, sẽ không thành vấn đề nếu giá trị mặc định được chỉ định trên thực hiện, nhưng sau đó nếu bạn vạch trần lớp bê tông của mình làm giao diện (sử dụng một số khung IOC để tiêm lớp bê tông chẳng hạn) thì thực sự không có điểm có giá trị mặc định là người gọi sẽ phải luôn cung cấp giá trị đó.

+16

Vì chúng là tùy chọn? – Oded

+1

Nhưng bạn có thể truyền đối tượng đối tượng sang 'MyInterface' và gọi nó với tham số tùy chọn:' ((MyInterface) obj) .TestMethod(); '. –

+5

@oded - nhưng nếu bạn nói thông số này là tùy chọn trên hợp đồng, tại sao bạn cho phép người triển khai không làm cho tùy chọn đó trở thành tùy chọn? điều đó không chỉ gây nhầm lẫn cho bất kỳ ai muốn sử dụng hợp đồng? – theburningmonk

Trả lời

193

UPDATE: This question was the subject of my blog on May 12th 2011. Thanks for the great question!

Giả sử bạn có một giao diện như bạn mô tả, và một trăm lớp mà thực hiện nó. Sau đó, bạn quyết định thực hiện một trong các tham số của một trong các phương thức của giao diện tùy chọn. Bạn có gợi ý rằng điều đúng đắn cần làm là dành cho trình biên dịch để buộc nhà phát triển tìm mọi cách triển khai phương thức giao diện đó và làm cho tham số tùy chọn không?

Giả sử chúng tôi đã làm điều đó.Bây giờ giả sử các nhà phát triển không có mã nguồn để thực hiện:


// in metadata: 
public class B 
{ 
    public void TestMethod(bool b) {} 
} 

// in source code 
interface MyInterface 
{ 
    void TestMethod(bool b = false); 
} 
class D : B, MyInterface {} 
// Legal because D's base class has a public method 
// that implements the interface method 

Làm thế nào là tác giả của D phải làm công việc này? Họ có cần thiết trong thế giới của bạn để gọi điện cho tác giả của B trên điện thoại và yêu cầu họ gửi cho họ phiên bản B mới mà làm cho phương pháp có thông số tùy chọn không?

Điều đó sẽ không bay. Điều gì sẽ xảy ra nếu hai người gọi điện cho tác giả của B và một trong số họ muốn mặc định là đúng và một trong số họ muốn nó là sai? Nếu tác giả của B đơn giản từ chối chơi cùng thì sao?

Có lẽ trong trường hợp đó họ sẽ được yêu cầu để nói:

class D : B, MyInterface 
{ 
    public new void TestMethod(bool b = false) 
    { 
     base.TestMethod(b); 
    } 
} 

Tính năng đề xuất dường như để thêm rất nhiều bất tiện cho các lập trình viên không có sự gia tăng tương ứng trong điện đại diện. Lợi ích hấp dẫn của tính năng này giúp biện minh cho chi phí tăng lên cho người dùng là gì?

+0

bây giờ bạn đặt nó như thế, nó không có ý nghĩa để có một hạn chế trên lớp thực hiện để làm theo việc sử dụng cùng một giá trị mặc định như giao diện. – theburningmonk

+0

Tôi chưa bao giờ nghĩ đến nỗi đau có thể gây ra điều đó. Tôi đoán cách duy nhất để làm cho nó cảm thấy như các phương thức giao diện có các đối số tùy chọn bằng nhau trong bất kỳ việc thực hiện nào, là có các phương thức mở rộng trong giao diện xử lý các tình trạng quá tải – Fede

+3

Sẽ có bất kỳ khả năng nào trong tương lai. để chỉ định triển khai "mặc định"? Nó có vẻ đơn giản về mặt khái niệm: tạo một lớp chung chung tĩnh với một số siêu dữ liệu đặc biệt để giữ các phương thức và khi xây dựng giao diện vtable cho một lớp thực hiện giao diện, điền vào bất kỳ điểm nào bị thiếu với các điểm tương ứng trong "phương thức mặc định" thích hợp lớp học. Thực tế là các phương thức struct truyền 'this' theo tham chiếu trong khi các phương thức lớp truyền 'this' theo giá trị có thể được xử lý bằng cách có một lớp tĩnh cho cấu trúc và một cho lớp. – supercat

24

Vì thông số mặc định được giải quyết tại thời gian biên dịch, không phải thời gian chạy. Vì vậy, các giá trị mặc định không thuộc về đối tượng đang được gọi, mà là đối với loại tham chiếu mà nó đang được gọi.

45

Thông số tùy chọn chỉ được gắn thẻ với thuộc tính. Thuộc tính này yêu cầu trình biên dịch chèn giá trị mặc định cho tham số đó tại trang gọi.

Cuộc gọi obj2.TestMethod(); được thay thế bằng obj2.TestMethod(false); khi mã C# được biên dịch sang IL và không phải lúc JIT-time.

Vì vậy, theo cách nó luôn là người gọi cung cấp giá trị mặc định với các thông số tùy chọn. Điều này cũng có hậu quả trên phiên bản nhị phân: Nếu bạn thay đổi giá trị mặc định nhưng không biên dịch lại mã gọi, nó sẽ tiếp tục sử dụng giá trị mặc định cũ.

Mặt khác, ngắt kết nối này có nghĩa là bạn không thể luôn sử dụng lớp bê tông và giao diện thay thế lẫn nhau.

Bạn đã không thể thực hiện điều đó nếu phương thức giao diện là implemented explicitly.

+1

Bạn có thể buộc người triển khai triển khai một cách rõ ràng hay không ? – crush

5

Các thông số tùy chọn giống như thay thế macro từ những gì tôi hiểu. Chúng không thực sự là tùy chọn từ quan điểm của phương thức. Một tạo tác của đó là hành vi mà bạn thấy nơi bạn nhận được các kết quả khác nhau nếu bạn truyền tới một giao diện.

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