Những nhược điểm để ánh xạ định danh tích phân vào enums là gì?


16

Tôi đã suy nghĩ về việc tạo các loại tùy chỉnh cho các định danh như thế này:

public enum CustomerId : int { /* intentionally empty */ }
public enum OrderId : int { }
public enum ProductId : int { }

Động lực chính của tôi cho việc này là để ngăn chặn loại lỗi mà bạn vô tình truyền một orderItemId cho một chức năng đang mong đợi một orderItemDetailId.

Dường như enums hoạt động trơn tru với mọi thứ tôi muốn sử dụng trong một ứng dụng web .NET thông thường:

  • Định tuyến MVC hoạt động tốt
  • Tuần tự hóa JSON hoạt động tốt
  • Mỗi ORM tôi có thể nghĩ là hoạt động tốt

Vì vậy, bây giờ tôi tự hỏi, "tại sao tôi không nên làm điều này?" Đây là những nhược điểm duy nhất tôi có thể nghĩ đến:

  • Nó có thể gây nhầm lẫn cho các nhà phát triển khác
  • Nó giới thiệu sự không nhất quán trong hệ thống của bạn nếu bạn có bất kỳ định danh không tách rời nào.
  • Nó có thể yêu cầu đúc thêm, như (CustomerId)42. Nhưng tôi không nghĩ rằng đây sẽ là một vấn đề, vì định tuyến ORM và MVC thường sẽ trao trực tiếp cho bạn các giá trị của loại enum.

Vì vậy, câu hỏi của tôi là, tôi đang thiếu gì? Đây có lẽ là một ý tưởng tồi, nhưng tại sao?



3
Đây được gọi là "microtyping", bạn có thể google xung quanh (ví dụ: đây là cho Java, chi tiết thì khác, nhưng động lực là như nhau)
qbd 2/2/2016

Tôi đã gõ hai câu trả lời một phần và sau đó xóa chúng vì tôi nhận ra mình đang nghĩ về điều này sai. Tôi đồng ý với bạn rằng "Đây có lẽ là một ý tưởng tồi, nhưng tại sao?"
2023861

Câu trả lời:


7

Đó là một ý tưởng tuyệt vời để tạo loại cho mọi loại định danh, chủ yếu là vì những lý do bạn đã nêu. Tôi sẽ không làm điều đó bằng cách triển khai kiểu như enum bởi vì làm cho nó trở thành một cấu trúc hoặc lớp thích hợp cung cấp cho bạn nhiều tùy chọn hơn:

  • Bạn có thể thêm chuyển đổi ngầm định vào int. Khi bạn nghĩ về nó, đó là một hướng khác, int -> CustomerId, đó là một vấn đề đáng được xác nhận rõ ràng từ người tiêu dùng.
  • Bạn có thể thêm các quy tắc kinh doanh xác định những định danh nào được chấp nhận và những gì không. Đây không chỉ là về việc kiểm tra yếu xem liệu int có tích cực hay không: đôi khi, danh sách tất cả các ID có thể được lưu trong cơ sở dữ liệu, nhưng chỉ thay đổi trong quá trình triển khai. Sau đó, bạn có thể dễ dàng kiểm tra xem ID đã cho có tồn tại so với kết quả được lưu trong bộ nhớ cache của truy vấn phù hợp không. Bằng cách này, bạn có thể đảm bảo rằng ứng dụng của bạn sẽ thất bại nhanh chóng khi có dữ liệu không hợp lệ.
  • Các phương thức trên mã định danh có thể giúp bạn thực hiện kiểm tra tồn tại DB đắt tiền hoặc có được đối tượng thực thể / miền tương ứng.

Bạn có thể đọc về việc thực hiện điều này trong bài viết Chức năng C #: Nỗi ám ảnh nguyên thủy .


1
Tôi muốn nói rằng bạn gần như chắc chắn vì vậy không muốn bao bọc từng int trong một lớp mà trong một cấu trúc
jk.

Nhận xét tốt, tôi cập nhật câu trả lời một chút.
Lukáš Lánský

3

Đó là một hack thông minh, nhưng vẫn là một hack trong đó lạm dụng một tính năng cho một cái gì đó không phải là mục đích dự định. Hacks có chi phí bảo trì, do đó, bạn không thể tìm thấy bất kỳ nhược điểm nào khác, nó cũng cần có lợi ích đáng kể so với cách thức thành ngữ hơn để giải quyết vấn đề tương tự.

Cách thành ngữ sẽ là tạo kiểu trình bao bọc hoặc cấu trúc với một trường duy nhất. Điều này sẽ cung cấp cho bạn sự an toàn cùng loại theo cách rõ ràng và thành ngữ hơn. Mặc dù đề xuất của bạn được thừa nhận thông minh, tôi không thấy bất kỳ lợi thế đáng kể nào khi sử dụng các loại trình bao bọc.


1
Ưu điểm chính của enum là nó "chỉ hoạt động" theo cách bạn muốn với MVC, serialization, ORM, v.v. Tôi đã tạo các loại tùy chỉnh (structs và class) trong quá khứ và cuối cùng bạn viết nhiều mã hơn bạn phải có để làm cho các khung / thư viện đó hoạt động với các loại tùy chỉnh của bạn.
default.kramer

Tuần tự hóa nên hoạt động trong suốt một trong hai cách, nhưng ví dụ. ORM là bạn cần phải cấu hình một số loại chuyển đổi rõ ràng. Nhưng đây là giá của một ngôn ngữ đánh máy mạnh mẽ.
JacquesB

2

Từ POV của tôi, ý tưởng là tốt. Ý định đưa ra các loại khác nhau cho các lớp định danh không liên quan, và mặt khác thể hiện ngữ nghĩa thông qua các loại và để trình biên dịch kiểm tra nó, là một cách tốt.

Tôi không biết làm thế nào nó hoạt động trong .NET Performance-khôn ngoan, ví dụ như các giá trị enum nhất thiết phải được đóng hộp. Mã OTOH hoạt động với cơ sở dữ liệu có khả năng bị ràng buộc I / O và các mã định danh được đóng hộp sẽ không bị tắc nghẽn.

Trong một thế giới hoàn hảo, các định danh sẽ là bất biến và chỉ có thể so sánh cho sự bình đẳng; byte thực tế sẽ là một chi tiết thực hiện. Các mã định danh không liên quan sẽ có các loại không tương thích, do đó bạn không thể sử dụng loại này cho loại khác. Giải pháp của bạn thực tế phù hợp với hóa đơn.


-1

Bạn không thể làm điều này, enums phải được xác định trước. Vì vậy, trừ khi bạn sẵn sàng xác định trước toàn bộ phổ các giá trị có thể có của id khách hàng, loại của bạn sẽ vô dụng.

Nếu bạn sử dụng, bạn sẽ bất chấp mục tiêu chính của mình là ngăn chặn việc vô tình gán id loại A cho id loại B. Vì vậy, enums không hữu ích cho mục đích của bạn.

Điều này sẽ đưa ra câu hỏi mặc dù nó sẽ hữu ích để tạo các loại của bạn cho id khách hàng, id đơn hàng và id sản phẩm bằng cách giảm dần từ Int32 (hoặc Guid). Tôi có thể nghĩ ra một lý do tại sao điều này sẽ sai.

Mục đích của một id là nhận dạng. Các kiểu tích phân đã hoàn hảo cho việc này, chúng không nhận được bất kỳ nhận dạng nào nữa bằng cách giảm dần từ chúng. Không có chuyên môn cần thiết cũng không mong muốn, thế giới của bạn sẽ không được thể hiện tốt hơn bằng cách có các loại khác nhau cho định danh. Vì vậy, từ góc độ OO, nó sẽ là xấu.

Với đề xuất của bạn, bạn muốn nhiều hơn an toàn kiểu, bạn muốn an toàn giá trị và đó là ngoài phạm vi mô hình, đó là một vấn đề hoạt động.


1
Không, enums không phải được xác định trước trong .NET. Và vấn đề là việc truyền hầu như không bao giờ xảy ra, ví dụ như public ActionResult GetCustomer(CustomerId custId)không cần truyền - khung MVC sẽ cung cấp giá trị.
default.kramer

2
Tôi không đồng ý. Đối với tôi, nó có ý nghĩa hoàn hảo từ quan điểm OO. Int32 không có ngữ nghĩa, đó hoàn toàn là loại "kỹ thuật". Nhưng tôi có nhu cầu về loại Định danh trừu tượng phục vụ mục đích xác định các đối tượng và được thực hiện dưới dạng Int32 (nhưng có thể dài hoặc bất cứ điều gì, không thực sự quan trọng). Chúng tôi có các chuyên môn cụ thể như ProductId xuất phát từ Mã định danh xác định phiên bản cụ thể của ProductId. Không có ý nghĩa logic nào khi gán giá trị của OrderItemId cho ProductId (rõ ràng là một lỗi) vì vậy thật tuyệt khi hệ thống loại có thể bảo vệ chúng ta khỏi điều này.
qbd

1
Tôi không biết C # có linh hoạt về việc sử dụng enum không. Nó chắc chắn là khó hiểu đối với tôi khi là một nhà phát triển đã quen với thực tế (?) Rằng các enum là, liệt kê các giá trị có thể. Họ thường chỉ định một loạt các id được đặt tên. Vì vậy, bây giờ loại này bị "lạm dụng" theo nghĩa là không có phạm vi và không có tên, chỉ có loại còn lại. Và rõ ràng, loại này cũng không an toàn. Một điều nữa: ví dụ rõ ràng là một ứng dụng cơ sở dữ liệu và đến một lúc nào đó "enum" của bạn sẽ được ánh xạ đến một trường loại không thể tách rời tại thời điểm mà bạn sẽ mất loại được cho là an toàn.
Martin Maat
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.