2017-06-23 65 views
5

Hãy tưởng tượng các thông số này là từ một dll bên ngoài. Một lớp học mà thực hiện một giao diện một cách rõ ràng:Mục đích nhằm che giấu việc triển khai giao diện rõ ràng của lớp cơ sở mà không cần cảnh báo?

public interface IDebug 
{ 
    string GetImportantInfo(); 
} 
public class ExternalClass : IDebug 
{ 
    public void DoSomethingImportant() 
    { 
     System.Diagnostics.Debug.WriteLine("Something important was done..."); 
    } 
    string IDebug.GetImportantInfo() //Explicit implementation 
    { 
     DoSomethingImportant(); 
     return nameof(ExternalClass); 
    } 
} 

Rồi một này là từ mã nội bộ, nơi bạn biết bạn cần phải thực hiện các giao diện:

public class Debug : ExternalClass, IDebug 
{ 
    public string GetImportantInfo() 
    { 
     return nameof(Debug); 
    } 
} 

Bây giờ khi tôi đang gọi Debug 's GetImportantInfo() phương pháp từ các lớp con, việc thực hiện rõ ràng trong lớp cha không được gọi:

static void Main(string[] args) 
{ 
    IDebug test = new Debug(); 
    var impInfo = test.GetImportantInfo(); 
    System.Diagnostics.Debug.WriteLine(impInfo); //"Debug" 
} 

Và gợi ý nhẹ duy nhất tôi dường như nhận được là Tôi không nhận được một lỗi biên dịch khi thêm giao diện IDebug đến lớp Debug, mà không thực hiện phương pháp này:

public class Debug : ExternalClass, IDebug 
{ 
} 

Tại sao không có cảnh báo biên dịch khi bạn ghi đè lên thực hiện của một lớp cha như thế này? Nếu lớp cơ sở thực hiện nó ngầm, tôi nhận được một cảnh báo biên dịch yêu cầu tôi sử dụng từ khóa new. Nhưng sử dụng từ khóa new để ghi đè phương thức được triển khai rõ ràng sẽ đưa ra cảnh báo biên dịch:

Thành viên 'Program.Debug.GetImportantInfo()' không ẩn thành viên được kế thừa. Từ khóa mới không bắt buộc.

Có mục đích dự định cho điều này hay đây là lỗi không? Nếu nó được dự định, lý do chính thức là gì?

+0

Vâng, bạn không nên kế thừa từ bất kỳ lớp nào mà không hoàn toàn hiểu nó ngay từ đầu. Việc biết những giao diện mà lớp cơ sở thực hiện (trực tiếp hay không) có vẻ như là một điều hợp lý để mong đợi. Xem xét điều này và biết làm thế nào C# * giao diện tái thực hiện * hoạt động nên là đủ để tránh cảnh báo – InBetween

+0

Ngoài ra, cảnh báo bạn nhận được khi giao diện được thực hiện ngầm trong lớp cơ sở có ít để làm với giao diện thực hiện ở tất cả; phương pháp cũ đơn giản của nó là ẩn náu. – InBetween

+0

Bạn hoàn toàn miễn phí để có ý kiến ​​đó. Nhưng về cơ bản, tôi đánh giá lời khuyên của bạn là "đừng phạm sai lầm". Giả định rằng _everyone_ là không thể sai lầm, là một kỳ vọng không thể đối với tôi. Việc vội vàng hoặc bị quên là hai trường hợp sử dụng bình thường, điều này có thể xảy ra. Và đột nhiên bạn có thể dành một thời gian dài cố gắng để gỡ lỗi các hành vi bất ngờ. Tôi không thấy một sự khác biệt giữa sự cần thiết của "phương pháp cũ tốt ẩn" và điều này. –

Trả lời

0

Nếu bạn sử dụng Triển khai rõ ràng hơn so với phương thức không hiển thị trong lớp của bạn mà không được truyền tới giao diện. Bạn sẽ không thể gọi

new ExternalClass().GetImportantInfo() 

nhưng bạn có thể gọi

((IDebug)new ExternalClass()).GetImportantInfo(); 

Bởi vì từ khóa mới thực hiện Explicit là không cần thiết. Bạn thậm chí có thể thêm cả hai triển khai trong một lớp:

public class ExternalClass : IDebug 
    { 
     string IDebug.GetImportantInfo() //Explicit implementation 
     { 
      return "Explicit"; 
     } 
     public string GetImportantInfo() 
     { 
      return nameof(ExternalClass); 
     } 
    } 

Ngoài ra lớp Debug của bạn không phải kế thừa giao diện IDebug khi nó thừa kế ExternalClass. Resharper sẽ cho bạn thấy điều này là dư thừa.

+0

Có - nhưng câu hỏi là tại sao tôi có thể ẩn việc triển khai rõ ràng lớp cơ sở mà không nhận được cảnh báo rằng tôi đang ẩn nó. Nếu 'Debug' không thực hiện' IDebug' và tôi gọi 'test.GetImportantInfo();' như trong câu hỏi, thì việc thực hiện rõ ràng được gọi. Tôi buồn là không có ReSharper hiện tại, nhưng bất kể - nếu bạn muốn triển khai thực hiện của riêng bạn của một lớp cơ sở 'thực hiện ngầm định, bạn có thể gọi 'base.GetImportantInfo()'. Khi nó được thực hiện một cách rõ ràng trong lớp cơ sở, tôi sẽ không có quyền truy cập vào 'base.GetImportantInfo()' –

+0

Hãy xem [this] (https://msdn.microsoft.com/en-us/library/aa664594% 28v = vs.71% 29.aspx? F = 255 & MSPPError = -2147217396) và [that] (https://msdn.microsoft.com/en-us/library/aa664593%28v=vs.71%29.aspx? f = 255 & MSPPError = -2147217396) –

1

Vấn đề ở đây là bạn đang sử dụng một chút tính năng được biết đến của ngôn ngữ: Giao diện tái thực hiện:

public class Debug : ExternalClass, IDebug 
{ 
    public string GetImportantInfo() 
    { 
     return nameof(Debug); 
    } 
} 

Tại sao các bạn redeclaring rằng Debug thực hiện IDebug nếu ExternalClass đã thực hiện? Bạn đang tái triển khai giao diện, và bởi vì bạn đang làm điều đó, bạn sẽ không nhận được cảnh báo; trình biên dịch giả định bạn biết bạn đang làm gì.

Nếu bạn muốn hành vi mà bạn dường như muốn, chỉ cần không tái thực hiện các giao diện:

public class Debug : ExternalClass 
{ 
    public string GetImportantInfo() 
    { 
     return nameof(Debug); 
    } 
} 

Nếu lớp cơ sở thực hiện nó mặc nhiên, tôi nhận được một cảnh báo biên dịch nói với tôi để sử dụng từ khóa mới.

Cảnh báo này không liên quan gì đến việc triển khai giao diện. Cảnh báo đơn giản là do phương thức ẩn, bạn có hai phương thức có cùng chữ ký; IDebug là một yếu tố không ở đây, bạn có thể đặt nó ra khỏi phương trình và bạn vẫn sẽ nhận được cảnh báo tương tự.

Trong trường hợp của đồng nghiệp, anh ấy nói anh ấy phải triển khai cả lớp cơ sở lẫn giao diện vì đó là giao diện dựa trên sự kiện.

Vâng, sau đó yêu cầu đồng nghiệp của bạn tìm hiểu xem anh ta muốn gì. Nếu bạn thực hiện lại giao diện, sau đó bất kỳ cuộc gọi nào đến DoSomething, có thể thông qua một tham chiếu đã nhập Debug hoặc một tham chiếu đã nhập IDebug, nên gọi hành vi được thực hiện lại. Bất kỳ hành vi nào khác sẽ là bất ngờ và vô cùng hoang mang.

Mặt khác, nếu bạn cần phải giữ cho hành vi orignal của lớp cơ sở nếu gọi DoSomething() thông qua một tài liệu tham khảo IDebug gõ sau đó không tái thực hiện các giao diện. Bạn đang đề xuất phương án thay thế nào khác?

Điều này có nghĩa là bạn nên biết những giao diện nào mà lớp cơ sở triển khai? Vâng vâng, tất nhiên. Tôi tìm thấy câu hỏi của bạn về lý do tại sao bất cứ ai nên biết những gì giao diện bất kỳ lớp học nào bạn sẽ kế thừa từ thực hiện sâu sắc đáng lo ngại phải trung thực.

+0

@Evk Tất nhiên nó sẽ thay đổi mọi thứ. '((IDebug) gỡ lỗi) .DoSomething()' sẽ gọi thực hiện rõ ràng, 'debug.DoSomething()' wont. – InBetween

+0

Có nhận xét của tôi về "không có sự khác biệt nào khác" là gây hiểu nhầm. Tuy nhiên, tôi nghĩ câu hỏi không phải là về điều này. OP thừa hưởng một số lớp cơ sở, muốn triển khai giao diện IDebug và muốn cảnh báo nếu giao diện đó đã được triển khai trong lớp cơ sở, để không vô tình ghi đè lên việc thực hiện cha mẹ. – Evk

+0

"Đơn giản đừng làm vậy". Vì vậy, bạn có nói rằng bạn đang phải kiểm tra tất cả các giao diện được thực hiện bởi tất cả các lớp học? Đồng nghiệp của tôi đã gặp phải điều này và không nhận ra rằng lớp cha cũng đã triển khai giao diện đó. Thực tế là nó được cho là "giả định" rằng bạn biết điều này, tấn công tôi như là lẻ, vì bạn nhận được một cảnh báo biên dịch khi bạn ẩn một triển khai ngầm định. Trong trường hợp của đồng nghiệp của tôi, anh ấy nói anh ấy phải thực hiện cả lớp cơ sở lẫn giao diện vì nó là một giao diện dựa trên sự kiện. –

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