Lạm dụng thuốc generic là gì?


35

Trong khi xem xét một số mã, tôi nhận thấy cơ hội để thay đổi nó để sử dụng thuốc generic. Mã (obfuscated) trông giống như:

public void DoAllTheThings(Type typeOfTarget, object[] possibleTargets)
{
    var someProperty = typeOfTarget.GetProperty(possibleTargets[0]);
    ...
}

Mã này có thể được thay thế bằng generic, như vậy:

public void DoAllTheThings<T>(object[] possibleTargets[0])
{
    var someProperty = type(T).getProperty(possibleTargets[0]);
    ...
}

Trong nghiên cứu những lợi ích và thiếu sót của phương pháp này, tôi đã tìm thấy một thuật ngữ gọi là lạm dụng chung . Xem:

Câu hỏi của tôi có hai phần:

  1. Có bất kỳ lợi ích nào khi chuyển sang thuốc generic như thế này không? (Hiệu suất? Khả năng đọc?)
  2. Lạm dụng Generics là gì? Và việc sử dụng chung chung mỗi khi có một tham số loại là lạm dụng ?

2
Tôi bối rối. Bạn biết tên của tài sản trước nhưng không phải là loại đối tượng để bạn sử dụng sự phản chiếu để có được một giá trị?
MetaFight

3
@MetaFight Tôi biết ví dụ phức tạp, mã thực tế sẽ dài và khó đặt ở đây. Bất kể, mục đích của câu hỏi của tôi là để xác định xem việc thay thế tham số Loại bằng chung chung được coi là hình thức tốt hay kém.
Cú pháp

12
Tôi đã luôn coi đó là lý do điển hình tại sao thuốc generic tồn tại (chơi chữ ngon không có ý định). Tại sao bạn phải tự đánh lừa khi bạn có thể tận dụng hệ thống loại của mình để làm điều đó cho bạn?
MetaFight

2
ví dụ của bạn là wierd, nhưng tôi có cảm giác nó chính xác là những gì nhiều thư viện IoD làm
Ewan

14
Không phải là một câu trả lời, nhưng đáng chú ý là ví dụ thứ hai kém linh hoạt hơn ví dụ thứ nhất. Làm cho hàm chung loại bỏ khả năng của bạn để vượt qua trong một kiểu thời gian chạy; Generics cần biết loại tại thời gian biên dịch.
KChaloux

Câu trả lời:


87

Khi thuốc generic được áp dụng một cách thích hợp, họ xóa mã thay vì chỉ sắp xếp lại nó. Chủ yếu, mã mà generic là tốt nhất trong việc loại bỏ là kiểu chữ, phản xạ và gõ động. Do đó, lạm dụng thuốc generic có thể được định nghĩa một cách lỏng lẻo là tạo mã chung mà không giảm đáng kể việc đánh máy, phản xạ hoặc gõ động so với triển khai không chung chung.

Liên quan đến ví dụ của bạn, tôi mong muốn sử dụng thuốc generic thích hợp để thay đổi object[]thành một T[]hoặc tương tự, và tránh Typehoặc typehoàn toàn. Điều đó có thể yêu cầu tái cấu trúc đáng kể ở nơi khác, nhưng nếu sử dụng thuốc generic là phù hợp trong trường hợp này, thì nó sẽ kết thúc đơn giản hơn khi bạn hoàn thành.


3
Đó là một điểm tuyệt vời. Tôi sẽ thừa nhận mã khiến tôi nghĩ về điều này đang thực hiện một số phản xạ khó đọc. Tôi sẽ xem nếu tôi có thể thay đổi object[]thành T[].
Cú pháp

3
Tôi thích loại bỏ so với sắp xếp lại đặc tính.
đồng.

13
Bạn đã bỏ lỡ một cách sử dụng chính của thuốc generic - đó là giảm trùng lặp. (Mặc dù bạn có thể giảm trùng lặp bằng cách giới thiệu bất kỳ tội lỗi nào khác mà bạn đề cập). Nếu nó giảm trùng lặp mà không loại bỏ bất kỳ kiểu chữ, phản xạ hoặc gõ động IMO thì không sao.
Michael Anderson

4
Câu trả lời tuyệt vời. Tôi muốn nói thêm rằng trong trường hợp cụ thể này, OP có thể cần phải chuyển sang giao diện thay vì thuốc generic. Dường như sự phản chiếu đang được sử dụng để truy cập các thuộc tính cụ thể của đối tượng; một giao diện phù hợp hơn nhiều để cho phép trình biên dịch xác định rằng các thuộc tính đó thực sự tồn tại.
jpmc26

4
@MichaelAnderson "xóa mã thay vì chỉ sắp xếp lại nó" bao gồm giảm trùng lặp
Caleth

5

Tôi sẽ sử dụng quy tắc không vô nghĩa: Generics, giống như tất cả các cấu trúc lập trình khác, tồn tại để giải quyết vấn đề . Nếu không có vấn đề để giải quyết cho thuốc generic, sử dụng chúng là lạm dụng.

Trong trường hợp cụ thể của generic, chúng chủ yếu tồn tại để trừu tượng khỏi các loại cụ thể, cho phép triển khai mã cho các loại khác nhau được xếp lại với nhau thành một khuôn mẫu chung (hoặc bất cứ ngôn ngữ nào của bạn xảy ra để gọi nó). Bây giờ, giả sử bạn có mã sử dụng một loại Foo. Bạn có thể thay thế loại đó bằng một cái chung T, nhưng nếu bạn chỉ cần mã đó để làm việc Foo, thì đơn giản là không có mã nào khác mà bạn có thể gấp nó lại với nhau. Do đó, không có vấn đề nào tồn tại để được giải quyết, do đó, việc bổ sung thêm chung chung sẽ chỉ phục vụ để giảm khả năng đọc.

Do đó, tôi khuyên bạn chỉ nên viết mã mà không sử dụng chung chung, cho đến khi bạn thấy cần phải giới thiệu chúng (vì bạn cần một lần khởi tạo thứ hai). Sau đó, và chỉ sau đó, là thời gian để cấu trúc lại mã để sử dụng generic. Bất kỳ việc sử dụng trước thời điểm đó là lạm dụng trong mắt tôi.


Điều này có vẻ hơi quá tầm thường, vì vậy hãy để tôi nhắc bạn:
Không có quy tắc nào mà không có ngoại lệ trong lập trình. Quy tắc này bao gồm.


Những suy nghĩ thú vị. Tuy nhiên, một chút viết lại các tiêu chí của bạn có thể giúp đỡ. Giả sử OP cần một "thành phần" mới để ánh xạ một int thành một chuỗi và ngược lại. Rõ ràng là nó giải quyết được một nhu cầu chung và có thể dễ dàng tái sử dụng trong tương lai nếu được đặt chung chung. Trường hợp này sẽ rơi vào định nghĩa của bạn về lạm dụng thuốc generic. Tuy nhiên, một khi nhu cầu cơ bản rất chung được xác định, sẽ không đáng để đầu tư một nỗ lực bổ sung không đáng kể vào thiết kế mà không bị lạm dụng?
Barshe

@Christophe Đó thực sự là một câu hỏi khó. Vâng, có một số tình huống thực sự tốt hơn để bỏ qua quy tắc của tôi (không có quy tắc nào mà không có ngoại lệ trong lập trình!). Tuy nhiên, trường hợp chuyển đổi chuỗi cụ thể thực sự khá liên quan: 1. Bạn cần xử lý riêng các loại số nguyên đã ký và không dấu. 2. Bạn cần xử lý chuyển đổi float tách biệt với chuyển đổi số nguyên. 3. Bạn có thể sử dụng lại cách triển khai cho các loại số nguyên lớn nhất có sẵn cho các loại nhỏ hơn. Bạn có thể muốn chủ động viết một trình bao bọc chung để thực hiện việc đúc, nhưng cốt lõi sẽ không có khái quát.
cmaster

1
Tôi tranh luận chống lại việc chủ động viết một cái chung chung (sử dụng trước thay vì sử dụng lại) như YAGNI. Khi bạn cần nó, sau đó tái cấu trúc.
Neil_UK

Khi viết câu hỏi này, tôi đã đưa ra lập trường "Viết nó như một cách chung chung nếu có thể để tiết kiệm việc sử dụng lại trong tương lai." Tôi biết đó là một chút cực đoan. Thật là mới mẻ khi thấy quan điểm của bạn ở đây. Cảm ơn!
Cú pháp

0

Các mã trông kỳ lạ. Nhưng nếu chúng ta gọi nó, nó sẽ đẹp hơn khi chỉ định loại là chung.

https://stackoverflow.com/questions/10955579/passing-just-a-type-as-a-parameter-in-c-sharp

Cá nhân tôi không thích những mâu thuẫn này làm cho mã cuộc gọi trông đẹp. ví dụ như toàn bộ điều 'thông thạo' và Phương pháp mở rộng.

Nhưng bạn phải thừa nhận rằng nó có một phổ biến sau đây. thậm chí microsoft sử dụng nó trong sự thống nhất chẳng hạn

container.RegisterType<IInterface,Concrete>()

0

Đối với tôi có vẻ như bạn đang đi đúng hướng ở đây, nhưng không hoàn thành công việc.

Bạn đã xem xét việc thay đổi object[]tham số Func<T,object>[]cho bước tiếp theo chưa?

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.