2016-02-17 17 views
5

Tôi có một tình huống thú vị nơi tôi muốn sử dụng một lớp cơ sở sử dụng một tham số kiểu để thực hiện một giao diện và cũng giữ mọi thứ KHÔ với các lớp kế thừa.Thực hiện chung giao diện với loại được chỉ định

public interface ICalculator 
{ 
    void Process(ICalculationModel calculationModel); 
} 

public abstract class CalculatorBase<T> :ICalculator where T : ICalculationModel 
{ 
    // Compiler moans that Process(ICalculationModel calculationModel) isn't implemented 
    public abstract void Process(T calculationModel); 
} 

public class PipeworkInspections : CalculatorBase<GasSafetyModel> 
{ 
    public override void Process(GasSafetyModel documentModel){ 
     //snip 
    } 
} 

Có điều gì đó tôi thiếu với mệnh đề 'where' chung hay gì đó không? Trong đầu của tôi điều này sẽ làm việc. Hay trình biên dịch cần chính xác thực hiện giống như định nghĩa giao diện?

Tôi không thể dễ dàng di chuyển thông số loại vào ICalculator vì có rất nhiều nơi mà nó được sử dụng mà không cần bất kỳ yêu cầu nào cho chung.

Đã xóa mọi thứ. Cảm ơn bạn về thông tin. Bây giờ rõ ràng là một giải pháp là làm cho giao diện lấy tham số kiểu. Tuy nhiên ICalculator được sử dụng ở một số nơi và được tham chiếu chỉ là ICalculator Bây giờ tôi nhận được lỗi trình biên dịch nếu tôi bỏ qua tham số kiểu trong Giao diện tham chiếu đến ICalculator ... Có cách nào để kiến ​​trúc sư này hoạt động không !?

+0

Tôi tin rằng nó phải giống với cách nó xuất hiện trong 'ICalculator'. Tuy nhiên, kể từ khi tôi làm chủ yếu là công cụ Java và không C#, tôi không thể nói rằng chắc chắn. – Powerlord

+0

Điều này không thể làm việc kể từ khi bạn có thể làm 'ICalculator c = new PipeworkInspections(); c.Process (new OtherModel()) 'không an toàn. Điều tốt nhất bạn có thể làm sẽ là implmement 'ICalculator.Process' và sau đó cast bên trong việc thực hiện chung. – Lee

Trả lời

0

Nếu đây làm việc thì bạn sẽ có thể nói điều gì đó như thế này:

PipeworkInspections pipeworks = new PipeworkInspections(); 
ICalculator calculator = pipeworks; 

NuclearPowerSafetyModel nuclearModel = new NuclearPowerSafetyModel(); 
calculator.Process(nuclearModel); // <-- Oops! 

Đó có lẽ không phải những gì bạn muốn ...

8

Trong đầu tôi nên làm việc này.

Sự cố xảy ra trong đầu bạn! :-) Điều này không nên hoạt động. Hãy xem tại sao.

interface ICage 
{ 
    void Enclose(Animal animal); 
} 
class ZooCage<T> : ICage where T : Animal 
{ 
    public void Enclose(T t) { ... } 
} 
... 

var giraffePaddock = new ZooCage<Giraffe>(); 
var cage = (ICage)giraffePaddock; 
var tiger = new Tiger(); 
icage.Enclose(tiger); 

Và bây giờ có một con cọp trong chuồng hươu cao cổ và cuộc sống tốt cho hổ nhưng không tốt cho hươu cao cổ. Đó là lý do tại sao điều này là bất hợp pháp.

Hoặc trình biên dịch có cần chính xác việc triển khai giống như định nghĩa giao diện không?

Thành viên triển khai thành viên giao diện phải khớp chính xác với chữ ký của phương pháp được triển khai. Ví dụ: bạn không thể sử dụng phương sai hiệp phương thức trả về:

interface I 
{ 
    Animal GetAnimal(); 
} 
class C : I 
{ 
    public Giraffe GetAnimal() { ... } // not legal. 
} 

Hợp đồng yêu cầu động vật; bạn cung cấp một con hươu cao cổ. Điều đó sẽ hoạt động, một cách hợp lý, nhưng điều này không hợp pháp trong C#. (Nó có trong C++.)

Xem bất kỳ câu hỏi nào trong trang web này về phương sai hiệp phương thức trả về vì lý do tại sao.

Tương tự như vậy cho loại tham số contravariance:

interface I 
{ 
    void PutMammal (Mammal mammal); 
} 
class C : I 
{ 
    public PutMammal(Animal animal) { ... } // not legal. 
} 

Một lần nữa, đây là một cách logic hợp lý; hợp đồng yêu cầu bạn mang theo động vật có vú, và điều này có bất kỳ động vật nào. Nhưng một lần nữa, điều này không hợp pháp.

Có một số phép biến đổi và biến đổi trong C#; xem bất kỳ câu hỏi nào về các chủ đề trên trang web này, hoặc duyệt các bài viết hiệp phương sai và đối ứng trên ericlippert.com hoặc blog msdn trước đây của tôi.

+0

Bạn có biết bất kỳ ngôn ngữ nào cho phép thực hiện giao diện (hoặc tương đương về mặt tinh thần) có thể bị so sánh với các đối số của phương thức không? Tôi đã nghe nói về một số phương sai hiệp phương thức trả về (bạn vừa đề cập đến C++), nhưng không phải là tham số contravariance. – Servy

+0

@Servy: Eiffel có thể? Tôi dường như nhớ lại nghe điều gì đó về Eiffel có tính năng đó. Tôi đã không bao giờ sử dụng Eiffel mặc dù, vì vậy tôi không thể nói chắc chắn. C# của khóa học cho phép contravariance tham số khi chuyển đổi một phương pháp cho một đại biểu, mà là một phần của một tương đương đạo đức tôi giả sử; bạn có thể nghĩ về một đại biểu như một giao diện với một phương thức gọi là Invoke. –

+0

@Servy: Tôi đã tìm kiếm nó. Eiffel hỗ trợ thông số * không an toàn * hiệp phương sai *, đó là lý do tại sao nó bị mắc kẹt trong đầu tôi. Sather là một ngôn ngữ giống như Eiffel hỗ trợ contravariance tham số. –

0

giao diện của bạn nói bất kỳ lớp thực hiện nó sẽ cung cấp phương pháp này:

void Process(ICalculationModel calculationModel); 

Bây giờ rõ ràng là PipeworkInspections không không. Nó không có phương thức Process chấp nhận bất kỳ ICalculationModel nào. CNTT chỉ có phương thức chấp nhận triển khai cụ thể củaICalculationModel. Vì vậy, trình biên dịch của bạn không thành công.

0

Có, bạn cần triển khai chính xác.

Là một thay thế bạn có thể làm interfaceProcess phương pháp chung nếu nó làm việc cho bạn:

public interface ICalculator<T> where T : ICalculationModel 
{ 
    void Process(T calculationModel); 
} 

public abstract class CalculatorBase<T> : ICalculator where T : ICalculationModel 
{ 
    public abstract void Process(T calculationModel); 
} 
0

Tôi đồng ý với câu trả lời Eric Lippert: bạn không thể. Và anh ta giải thích một cách rất tốt tại sao điều này lại xảy ra.

Nếu bạn thực sự muốn làm điều này, bạn có thể thêm dòng sau vào lớp trừu tượng của bạn, và nó sẽ biên dịch:

void ICalculator.Process(ICalculationModel calcMod) 
{ 
    Process((T)calcMod); 
} 

Nhưng bạn cần phải biết những gì bạn đang làm, nếu không bạn có thể có một số InvalidCastException khi chạy.

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