Một số cách sử dụng thực tế của công cụ sửa đổi mới của Wikipedia trong C # liên quan đến ẩn là gì?


21

Một đồng nghiệp và tôi đã xem xét hành vi của newtừ khóa trong C # vì nó áp dụng cho khái niệm ẩn. Từ tài liệu :

Sử dụng công cụ sửa đổi mới để ẩn một cách rõ ràng một thành viên được kế thừa từ một lớp cơ sở. Để ẩn một thành viên được kế thừa, hãy khai báo nó trong lớp dẫn xuất bằng cùng tên và sửa đổi nó với công cụ sửa đổi mới.

Chúng tôi đã đọc tài liệu này và chúng tôi hiểu về cơ bản nó làm gì và làm như thế nào. Những gì chúng tôi không thể thực sự nắm bắt được là tại sao bạn cần phải làm điều đó ngay từ đầu. Công cụ sửa đổi đã có ở đó từ năm 2003 và cả hai chúng tôi đã làm việc với .Net lâu hơn thế và nó không bao giờ xuất hiện.

Khi nào thì hành vi này là cần thiết trong một ý nghĩa thực tế (ví dụ: như được áp dụng cho một trường hợp kinh doanh)? Đây có phải là một tính năng đã vượt qua sự hữu ích của nó hay chỉ đơn giản là nó không đủ phổ biến trong những gì chúng ta làm (cụ thể là chúng ta làm các biểu mẫu web và ứng dụng MVC và một số yếu tố nhỏ WinForms và WPF)? Khi thử từ khóa này và chơi với nó, chúng tôi đã tìm thấy một số hành vi cho phép nó có vẻ hơi nguy hiểm nếu sử dụng sai.

Điều này nghe có vẻ hơi mở, nhưng chúng tôi đang tìm kiếm một trường hợp sử dụng cụ thể có thể được áp dụng cho một ứng dụng kinh doanh thấy công cụ cụ thể này hữu ích.


9
Có thể bạn cũng đã đọc nó, nhưng có một bài viết thú vị từ Eric Lippert (nhà phát triển trình biên dịch C #) về lý do tại sao phương thức ẩn được thêm vào C #: blog.msdn.com/b/ericlippert/archive/2008/05/21/ . Điều đó trả lời một phần câu hỏi của bạn, nhưng tôi không có sẵn một trường hợp kinh doanh cho bạn nên tôi đưa nó vào một bình luận.
Jalayn

3
@Jalayn: Trường hợp kinh doanh được Eric thảo luận trong bài đăng này: blog.msdn.com/b/ericlippert/archive/2004/01/07/ trên
Brian

Câu trả lời:


22

Bạn có thể sử dụng nó để bắt chước hiệp phương sai kiểu trả về. Giải thích của Eric Lippert . Eric cung cấp mã ví dụ này:

abstract class Enclosure
{
    protected abstract Animal GetContents();
    public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
    public new Fish Contents() { ... }
    protected override Animal GetContents() { return this.Contents(); }
}

Đây là một công việc xung quanh. public override Fish Contents() { ... }là không hợp pháp, mặc dù được an toàn.

Nói chung, bạn không nên sử dụng phương thức ẩn, vì nó gây nhầm lẫn cho người tiêu dùng của lớp bạn (ví dụ cụ thể ở trên không gặp phải vấn đề này). Chỉ cần đặt tên cho phương thức mới của bạn một cái gì đó khác nếu bạn không muốn ghi đè một phương thức hiện có.

Một tình huống trong thế giới thực có khả năng bạn cần ẩn phương thức là nếu nhà cung cấp của lớp cơ sở đã thêm một phương thức chung mà bạn đã thêm vào một lớp dẫn xuất. Một chương trình như vậy sẽ biên dịch (và đưa ra cảnh báo) mà không cần từ khóa mới, nhưng thêm vào new, "Tôi biết phiên bản của phương thức này đang thay thế phiên bản của lớp cơ sở. Điều này thật kinh khủng và khó hiểu, nhưng chúng tôi bị mắc kẹt với nó." Điều đó vẫn tốt hơn là buộc lớp dẫn xuất đổi tên phương thức của họ.

Chỉ cho phép phương thức dẫn xuất được coi là ghi đè sẽ gây ra vấn đề. Bỏ qua bất kỳ mối quan tâm nào với việc triển khai trình biên dịch, phương thức mới này khác về mặt ngữ nghĩa so với phương thức cơ sở, nhưng tính đa hình sẽ khiến phương thức mới được gọi khi được yêu cầu gọi một phương thức có cùng tên.

Tình huống này được thảo luận chi tiết trong bài viết này của Eric Lippert.


1
+1 vì newlà điểm đánh dấu cho "điều này thật kinh khủng và khó hiểu".
Avner Shahar-Kashtan

Tôi nghĩ ví dụ của Eric rất hữu ích, nếu chỉ vì tôi ở trong một tình huống tương tự ... Tôi có một lớp cơ sở thực hiện một phương thức không cần thiết trả về TBase và một lớp dẫn xuất sẽ trả về một TDerive. Trong trường hợp này, nó cảm thấy như một điều ác cần thiết.
Kyle Baran

4

Tôi nghĩ rằng nó ở đó trong trường hợp bạn có thể cần nó để làm một cái gì đó mà các nhà thiết kế ngôn ngữ có thể không nghĩ đến. C # theo nhiều cách là một phản ứng đối với các phiên bản đầu tiên của java. Và một điều java đã làm là rất rõ ràng các nhà phát triển pigeonhole để loại bỏ khả năng của các nhà phát triển tự bắn vào chân mình. C # đã thực hiện một cách tiếp cận hơi khác và cung cấp cho các nhà phát triển thêm một chút sức mạnh trong việc cho phép các nhà phát triển thêm một vài cơ hội để tự bắn vào chân mình. Một ví dụ là unsafetừ khóa. Đây newtừ khóa là khác.

Bây giờ, nó có thể không hữu ích như unsafenhưng một khi bạn đã vào một thông số ngôn ngữ, thật khó để thoát ra khỏi một thông số ngôn ngữ.


5
Java không có tính năng mới vì Java coi tất cả các phương thức là ảo. Theo Eric Lippert, động lực để hỗ trợ mới là giải quyết vấn đề lớp cơ sở dễ vỡ. Sự tồn tại của cái mới là cần thiết cho việc sử dụng kinh doanh trong thế giới thực, không chỉ cho việc sử dụng thư viện cấp thấp. Java không có phương thức mới (và không có phương thức không ảo) có nghĩa là nếu một lớp cơ sở giới thiệu một phương thức mới đã được sử dụng trong các lớp dẫn xuất, mã hiện tại có thể bị phá vỡ, mặc dù thực tế là nhà phát triển của lớp cơ sở nên được cho phép để quên mã mà tiêu thụ nó.
Brian

3

Nó nói với người đọc rằng "Tôi cố tình che giấu việc thực hiện phương thức này của lớp cơ sở", trái ngược với tình cờ.


5
Điều này đánh tôi như cầu xin câu hỏi. OP biết những gì nó làm nhưng muốn biết tại sao.
Brian

0

Bạn có thể muốn có thành viên trước đó thông qua tên khác:

class VehicleClass
{
  public int AnyProperty
  {
    get; set;
  }

  public int AnyFunction() { return 0; }
} // VehicleClass

class IntermediateClass : VehicleClass
{
  public int PreviousAnyProperty
  {
    get { return AnyProperty; }
    set { AnyProperty = value  }
  }

  public int PreviousAnyFunction() { return AnyFunction(); }
} // IntermediateClass 

class CarClass : IntermediateClass
{
  public new int AnyProperty
  {
    get ; set ;
  }

  public new int AnyFunction() { return 5; }
} // class CarClass

class ExampleClass
{

  public static void Main()
  {
    using (CarClass MyCar = new CarClass())
    {
      int AnyInt1 = MyCar.PreviousAnyProperty;
      MyCar.PreviousAnyProperty = 7;

      int AnyInt2 = MyCar.PreviousAnyFunction();

      int AnyInt3 = MyCar.AnyProperty;
      MyCar.AnyProperty = 45;

      int AnyInt4 = MyCar.AnyFunction();
    }
  } // static void Main()

} // class CarClass

Chúc mừng.


Tôi quen thuộc với cách thức hoạt động của nó, nhưng câu hỏi của tôi thực sự là Tại sao bạn muốn có thành viên trước đó thông qua một tên khác? Điều này phá vỡ tất cả các loại hợp đồng, làm cho một số phần chung chung vô dụng.
Joel Etherton

@Joel Etherton: Như bạn có thể biết, đôi khi các nhà phát triển phải "chọn" người khác lập trình mã. Và chúng tôi có thể không được phép sửa đổi, có thể mở rộng các lớp. Và có thể yêu cầu sử dụng cả hai, thành viên trước đó & thành viên mới.
umlcat

0

Tôi đã tìm thấy nó khá hữu ích khi tạo một bộ thử nghiệm cho mã kế thừa. Nó cho phép tôi ẩn các phụ thuộc bên ngoài, như truy vấn cơ sở dữ liệu bên trong một phương thức được sử dụng bởi các phương thức khác. Để có thể kiểm tra các phương thức khác, tôi có thể ẩn logic gốc phụ thuộc vào tài nguyên bên ngoài mà không cần thêm từ khóa ảo vào các phương thức đó trong các lớp kiểm tra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.