Có vấn đề với việc sử dụng Reflection?


49

Tôi không biết tại sao, nhưng tôi luôn cảm thấy như mình "gian lận" khi tôi sử dụng sự phản chiếu - có thể đó là do hiệu suất mà tôi biết tôi đang thực hiện.

Một phần trong tôi nói, nếu đó là một phần của ngôn ngữ bạn đang sử dụng và nó có thể thực hiện những gì bạn đang cố gắng thì tại sao không sử dụng nó. Phần khác của tôi nói, phải có một cách tôi có thể làm điều này mà không cần sử dụng sự phản chiếu. Tôi đoán có lẽ nó phụ thuộc vào tình hình.

Các vấn đề tiềm năng tôi cần chú ý khi sử dụng sự phản chiếu là gì và tôi nên quan tâm đến chúng như thế nào? Cần bao nhiêu nỗ lực để chi tiêu để cố gắng tìm một giải pháp thông thường hơn?


2
Tôi đoán nó phụ thuộc vào ngôn ngữ và môi trường. Một số ủng hộ nó, thậm chí khuyến khích nó. Đôi khi khi làm việc trong Java tôi đã mong muốn được hỗ trợ phản chiếu tốt hơn.
Thất vọngWithFormsDesigner

18
Chà, tôi đoán không khó để ăn giữa "phản xạ gian lận" và việc sử dụng nó hợp lệ: Khi bạn kiểm tra các thành viên tư nhân hoặc sử dụng nó để gọi các phương thức riêng tư (để làm việc xung quanh các giao diện), thì rất có thể là gian lận. Khi bạn sử dụng nó để tương tác với các loại mà bạn không có kiến ​​thức về nó, thì có lẽ nó ổn (databinding, proxy, v.v.).
Falcon

1
Ngôn ngữ của bạn đang sử dụng là gì? Brainfuck không có sự phản chiếu và Python chỉ khác nhau.
Công việc

1
Tôi cũng không bao giờ hiểu tại sao nó được phép truy cập các phương thức riêng tư thông qua sự phản chiếu. Theo trực giác của tôi thì nên cấm.
Giorgio

3
Khó có thể tin rằng một câu hỏi kém như vậy lại có 27 câu hỏi mà không cần chỉnh sửa.
Aaronaught

Câu trả lời:


48

Không, đó không phải là gian lận - đó là một cách để giải quyết vấn đề trong một số ngôn ngữ lập trình.

Bây giờ, nó thường không phải là giải pháp tốt nhất (sạch nhất, đơn giản nhất, dễ bảo trì nhất). Nếu có một cách tốt hơn, thực sự sử dụng một cách đó. Tuy nhiên, đôi khi không có. Hoặc nếu có, nó phức tạp hơn rất nhiều, liên quan đến rất nhiều sự sao chép mã, v.v ... khiến cho nó không khả thi (khó duy trì trong thời gian dài).

Hai ví dụ từ dự án hiện tại của chúng tôi (Java):

  • một số công cụ kiểm tra của chúng tôi sử dụng sự phản chiếu để tải cấu hình từ các tệp XML. Lớp được khởi tạo có các trường cụ thể và trình tải cấu hình sử dụng sự phản chiếu để khớp với phần tử XML được đặt tên fieldXcho trường thích hợp trong lớp và để khởi tạo cái sau. Trong một số trường hợp, nó có thể xây dựng một hộp thoại GUI đơn giản từ các thuộc tính được xác định một cách nhanh chóng. Nếu không có sự phản ánh, điều này sẽ mất hàng trăm dòng mã trên một số ứng dụng. Vì vậy, sự phản chiếu đã giúp chúng tôi nhanh chóng kết hợp một công cụ đơn giản, không gây ồn ào và cho phép chúng tôi tập trung vào phần quan trọng (kiểm tra hồi quy ứng dụng web của chúng tôi, phân tích nhật ký máy chủ, v.v.) chứ không phải là không liên quan.
  • một mô-đun của ứng dụng web cũ của chúng tôi có nghĩa là xuất / nhập dữ liệu từ các bảng DB sang các trang tính Excel và quay lại. Nó chứa rất nhiều mã trùng lặp, trong đó tất nhiên các bản sao không giống hệt nhau, một số trong đó có lỗi, v.v ... Sử dụng sự phản chiếu, hướng nội và chú thích, tôi đã quản lý để loại bỏ hầu hết các bản sao, cắt giảm số lượng mã 5K đến dưới 2,4K, trong khi làm cho mã mạnh mẽ hơn và cách dễ dàng hơn để duy trì hoặc mở rộng. Bây giờ mô-đun đó đã không còn là vấn đề đối với chúng tôi - nhờ vào việc sử dụng phản xạ hợp lý.

Điểm mấu chốt là, giống như bất kỳ công cụ mạnh mẽ nào, sự phản chiếu cũng có thể được sử dụng để tự bắn vào chân bạn. Nếu bạn tìm hiểu khi nào và làm thế nào (không) sử dụng nó, nó có thể mang lại cho bạn các giải pháp thanh lịch và sạch sẽ cho các vấn đề khó khăn khác. Nếu bạn lạm dụng nó, bạn có thể biến một vấn đề đơn giản khác thành một mớ hỗn độn và xấu xí.


8
+1 Reflection cực kỳ hữu ích cho việc nhập / xuất dữ liệu khi bạn có các đối tượng trung gian vì lý do chuyển đổi.
Ed James

2
Nó cũng cực kỳ hữu ích trong các ứng dụng dựa trên dữ liệu - thay vì sử dụng một đống lớn if (propName = n) setN(propValue);, bạn có thể đặt tên cho các thẻ XML (tức là) của mình giống như các thuộc tính mã của bạn và chạy một vòng qua chúng. Phương pháp này cũng làm cho nó đơn giản hơn nhiều để thêm các thuộc tính sau này.
Michael K

Sự phản chiếu được sử dụng nhiều trong các giao diện Fluent, như FluentNHibernate.
Scott Whitlock

4
@Michael: Cho đến khi bạn quyết định đổi tên một trong những thuộc tính đó trong lớp và thấy rằng mã của bạn phát nổ. Nếu bạn không cần duy trì khả năng so sánh với những thứ mà chương trình của bạn tạo ra, điều đó tốt, nhưng tôi nghi ngờ đó không phải là hầu hết chúng ta.
Billy ONeal

1
@Billy, tôi không có ý mâu thuẫn với bạn, tôi đồng ý với những gì bạn viết. Mặc dù, ví dụ bạn đưa ra là IMHO thêm một chữ con của quy tắc chung "tránh thay đổi giao diện công cộng".
Péter Török

37

Đó không phải là gian lận. Nhưng nó thường là một ý tưởng tồi trong mã sản xuất vì ít nhất các lý do sau:

  • Bạn mất an toàn kiểu thời gian biên dịch - thật hữu ích khi trình biên dịch xác minh rằng một phương thức có sẵn tại thời gian biên dịch. Nếu bạn đang sử dụng sự phản chiếu, bạn sẽ gặp lỗi trong thời gian chạy có thể ảnh hưởng đến người dùng cuối nếu bạn không kiểm tra đủ tốt. Ngay cả khi bạn bắt lỗi, việc gỡ lỗi sẽ khó khăn hơn.
  • Nó gây ra lỗi khi tái cấu trúc - nếu bạn đang truy cập một thành viên dựa trên tên của nó (ví dụ: sử dụng chuỗi được mã hóa cứng) thì điều này sẽ không bị thay đổi bởi hầu hết các công cụ tái cấu trúc mã và bạn sẽ ngay lập tức gặp lỗi. khó theo dõi.
  • Hiệu suất chậm hơn - sự phản chiếu trong thời gian chạy sẽ chậm hơn so với các cuộc gọi phương thức / tra cứu biến được biên dịch tĩnh. Nếu thỉnh thoảng bạn chỉ thực hiện phản xạ thì điều đó không thành vấn đề, nhưng điều này có thể trở thành nút cổ chai hiệu năng trong trường hợp bạn thực hiện cuộc gọi qua phản xạ hàng nghìn hoặc hàng triệu lần mỗi giây. Tôi đã từng tăng tốc gấp 10 lần trong một số mã Clojure chỉ bằng cách loại bỏ tất cả sự phản chiếu, vì vậy, đây là một vấn đề thực sự.

Tôi đề nghị hạn chế sử dụng phản xạ trong các trường hợp sau:

  • Để tạo mẫu nhanh hoặc mã "vứt bỏ" khi đó là giải pháp đơn giản nhất
  • Đối với các trường hợp sử dụng phản xạ chính hãng , ví dụ công cụ IDE cho phép người dùng kiểm tra các trường / phương thức của một đối tượng tùy ý khi chạy.

Trong tất cả các trường hợp khác, tôi khuyên bạn nên tìm ra một cách tiếp cận để tránh sự phản chiếu. Xác định một giao diện với (các) phương thức thích hợp và triển khai nó trên tập hợp các lớp bạn muốn gọi (các) phương thức trên thường là đủ để giải quyết hầu hết các trường hợp đơn giản.


3
+1 - có một số trường hợp sử dụng để phản ánh; nhưng hầu hết thời gian tôi thấy các lập trình viên sử dụng nó, họ đang vượt qua các thiết kế với những sai sót nghiêm trọng. Xác định giao diện và cố gắng loại bỏ sự phụ thuộc vào sự phản chiếu. Giống như GOTO, nó có công dụng của nó, nhưng hầu hết trong số chúng không tốt. (Một số trong số họ là tốt, tất nhiên)
Billy ONeal

3
Hãy nhớ rằng các điểm trên có thể hoặc không thể áp dụng cho ngôn ngữ yêu thích của bạn. Chẳng hạn, sự phản chiếu không có hình phạt tốc độ trong Smalltalk, bạn cũng không mất an toàn thời gian biên dịch, vì tính toán hoàn toàn bị ràng buộc muộn.
Frank Shearar

Phản ánh trong D không có nhược điểm bạn đề cập. Vì vậy, tôi sẽ tranh luận rằng bạn đang đổ lỗi cho việc thực hiện trong một số ngôn ngữ hơn tha thứ cho chính nó. Tôi không biết nhiều về smalltalk, nhưng theo @Frank Shearar, nó cũng không có nhược điểm.
deadalnix

2
@deadalinx: Bạn đề cập đến nhược điểm nào? Có một số trong câu trả lời này. Vấn đề hiệu suất là điều duy nhất phụ thuộc vào ngôn ngữ.
Billy ONeal

1
Tôi nên nói thêm rằng vấn đề thứ hai - lỗi gây ra trong quá trình tái cấu trúc - có lẽ là nghiêm trọng nhất. Cụ thể, việc dựa vào một cái gì đó có một tên cụ thể bị phá vỡ ngay lập tức khi tên của thứ đó thay đổi. Do đó, các lỗi gây ra có thể ít hơn thông tin, trừ khi bạn rất cẩn thận.
Frank Shearar

11

Reflection chỉ là một hình thức lập trình meta khác, và cũng hợp lệ, như các tham số dựa trên loại mà bạn thấy trong hầu hết các ngôn ngữ hiện nay. Sự phản chiếu là mạnh mẽ và chung chung, và các chương trình phản chiếu là một thứ tự cao về khả năng duy trì (tất nhiên khi được sử dụng một cách chính xác) và hơn thế nữa so với các chương trình hoàn toàn hướng đối tượng hoặc theo thủ tục. Có, bạn phải trả giá hiệu suất - nhưng tôi sẵn sàng tham gia một chương trình chậm hơn, có thể duy trì nhiều hơn trong nhiều trường hợp, hoặc thậm chí là hầu hết các trường hợp.


2
+1, điều này giúp tôi hiểu phản xạ gì . Tôi là một lập trình viên C ++, và vì vậy tôi chưa bao giờ thực sự suy ngẫm. Điều này có ích. (Mặc dù tôi thú nhận rằng từ quan điểm của tôi, Reflection có vẻ như một nỗ lực hòa sự thiếu hụt trong ngôn ngữ C ++ Chúng tôi kẻ sử dụng các mẫu cho điều đó Vì vậy, tôi cho rằng bạn có thể nói như vậy về điều đó :)...
greyfade

4
Hiệu suất lại - trong một số trường hợp, bạn có thể sử dụng API phản chiếu để viết lại mã hiệu suất đầy đủ. Ví dụ: trong .NET, bạn có thể viết IL vào ứng dụng hiện tại - do đó mã "phản chiếu" của bạn có thể nhanh như bất kỳ mã nào khác (ngoại trừ bạn có thể loại bỏ rất nhiều if / other / anything, như bạn đã tìm ra các quy tắc chính xác)
Marc Gravell

@greyfade: Theo một nghĩa nào đó, các mẫu đang thực hiện phản xạ chỉ biên dịch theo thời gian. Có thể làm điều đó trong thời gian chạy có lợi thế là cho phép các khả năng mạnh mẽ được xây dựng trong ứng dụng mà không cần phải biên dịch lại. Bạn giao dịch hiệu suất để linh hoạt, một sự đánh đổi chấp nhận được nhiều thời gian hơn bạn mong đợi (dựa trên nền tảng C ++ của bạn).
Donal Fellows

Tôi không hiểu câu trả lời của bạn. Dường như bạn đang nói rằng các chương trình sử dụng sự phản chiếu có thể duy trì được nhiều hơn những chương trình không, vì nếu sự phản chiếu là một mô hình lập trình ưu việt sẽ thay thế các chương trình hướng đối tượng và hướng đối tượng nếu không cần hiệu suất.
DavidS 24/2/2015

8

Chắc chắn tất cả phụ thuộc vào những gì bạn đang cố gắng để đạt được.

Ví dụ, tôi đã viết một ứng dụng kiểm tra phương tiện sử dụng phương thức tiêm phụ thuộc để xác định loại phương tiện nào (tệp MP3 hoặc tệp JPEG) để kiểm tra. Vỏ cần thiết để hiển thị một lưới chứa thông tin thích hợp cho từng loại, nhưng nó không có kiến ​​thức về những gì nó sẽ hiển thị. Điều này được định nghĩa trong hội đồng đọc loại phương tiện đó.

Do đó, tôi đã phải sử dụng sự phản chiếu để có được số lượng cột để hiển thị và các loại và tên của chúng để tôi có thể thiết lập lưới chính xác. Điều đó cũng có nghĩa là tôi có thể cập nhật thư viện được chèn (hoặc tạo một thư viện mới) mà không thay đổi bất kỳ tệp mã hoặc cấu hình nào khác.

Cách duy nhất khác là có một tệp cấu hình cần được cập nhật khi tôi chuyển loại phương tiện đang được kiểm tra. Điều này sẽ giới thiệu một điểm thất bại khác cho ứng dụng.


1
"Chắc chắn tất cả phụ thuộc vào những gì bạn đang cố gắng để đạt được." +1
DaveShaw

7

Reflection là một công cụ tuyệt vời nếu bạn là một tác giả thư viện và do đó không có ảnh hưởng đến dữ liệu đến. Một sự kết hợp giữa phản xạ và lập trình meta có thể cho phép thư viện của bạn hoạt động trơn tru với những người gọi tùy ý, mà không cần phải nhảy qua các vòng tạo mã, v.v.

Mặc dù vậy, tôi cố gắng ngăn cản sự phản ánh trong mã ứng dụng ; ở lớp ứng dụng, bạn nên sử dụng các phép ẩn dụ khác nhau - giao diện, trừu tượng hóa, đóng gói, v.v.


Những thư viện như vậy thường khó sử dụng và tốt nhất nên tránh (ví dụ: Spring).
Sridhar Sarnobat

@Sridhar vì vậy bạn chưa bao giờ sử dụng bất kỳ API tuần tự hóa nào? Hoặc bất kỳ ORM / micro-ORM?
Marc Gravell

Tôi đã sử dụng chúng thông qua không có sự lựa chọn của riêng tôi. Nó đang làm mất tinh thần khi gặp phải những vấn đề tôi có thể tránh được nếu tôi không được bảo phải làm gì.
Sridhar Sarnobat

7

Reflection là tuyệt vời cho các công cụ xây dựng cho các nhà phát triển.

Vì nó cho phép môi trường xây dựng của bạn kiểm tra mã và có khả năng tạo ra các công cụ chính xác để thao tác / init kiểm tra mã.

Là một kỹ thuật lập trình chung, nó có thể hữu ích nhưng dễ vỡ hơn hầu hết mọi người tưởng tượng.

Một cách sử dụng phát triển thực sự cho sự phản chiếu (IMO) là nó làm cho việc viết một thư viện phát trực tuyến chung rất đơn giản (miễn là mô tả lớp của bạn không bao giờ thay đổi (sau đó nó trở thành một giải pháp rất dễ vỡ)).


Thật vậy, Spring "dễ vỡ hơn hầu hết mọi người tưởng tượng."
Sridhar Sarnobat

5

Sử dụng sự phản chiếu thường có hại trong các ngôn ngữ OO nếu không được sử dụng với nhận thức tuyệt vời.

Tôi đã mất đi số lượng câu hỏi xấu mà tôi đã thấy trên các trang web StackExchange

  1. Ngôn ngữ được sử dụng là OO
  2. Tác giả muốn tìm ra loại đối tượng nào đã được truyền vào và sau đó gọi một trong các phương thức của nó
  3. Tác giả từ chối chấp nhận rằng phản ánh là kỹ thuật sai và buộc tội bất cứ ai chỉ ra điều này là "không biết làm thế nào để giúp tôi"

Dưới đây những ví dụ điển hình.

Hầu hết quan điểm của OO là

  1. Bạn nhóm các hàm biết cách thao tác một cấu trúc / khái niệm với chính nó.
  2. Trong bất kỳ điểm nào trong mã của bạn, bạn nên biết đủ về loại đối tượng để biết nó có chức năng liên quan nào và yêu cầu nó gọi phiên bản cụ thể của các chức năng đó.
  3. Bạn đảm bảo sự thật của điểm trước bằng cách chỉ định loại đầu vào chính xác cho mọi chức năng và để mỗi chức năng không biết nhiều hơn (và không làm gì nhiều hơn) có liên quan.

Nếu tại bất kỳ điểm nào trong mã của bạn, điểm 2 không hợp lệ đối với một đối tượng bạn đã được thông qua thì một hoặc nhiều trong số này là đúng

  1. Đầu vào sai đang được cho ăn
  2. Mã của bạn có cấu trúc kém
  3. Bạn không biết bạn đang làm cái quái gì thế.

Các nhà phát triển có kỹ năng kém chỉ đơn giản là không có được điều này và tin rằng họ có thể được thông qua bất cứ điều gì trong bất kỳ phần nào của mã của họ và làm những gì họ muốn từ một bộ khả năng (được mã hóa cứng). Những kẻ ngốc sử dụng sự phản ánh rất nhiều .

Đối với các ngôn ngữ OO, chỉ cần phản chiếu trong hoạt động meta (trình nạp lớp, tiêm phụ thuộc, v.v.). Trong các bối cảnh đó, sự phản chiếu là cần thiết bởi vì bạn đang cung cấp một dịch vụ chung để hỗ trợ thao tác / cấu hình mã mà bạn không biết gì về lý do chính đáng và hợp pháp. Trong hầu hết mọi tình huống khác, nếu bạn đang tìm kiếm sự phản chiếu thì bạn đang làm gì đó sai và bạn cần tự hỏi tại sao đoạn mã này không biết đủ về đối tượng đã được truyền cho nó.


3

Một cách khác, trong trường hợp miền của các lớp được phản ánh được xác định rõ, là sử dụng sự phản chiếu cùng với siêu dữ liệu khác để tạo mã , thay vì sử dụng sự phản chiếu khi chạy. Tôi làm điều này bằng cách sử dụng FreeMarker / FMPP; có rất nhiều công cụ khác để lựa chọn. Ưu điểm của việc này là bạn kết thúc với mã "thực" có thể dễ dàng gỡ lỗi, v.v.

Tùy thuộc vào tình huống, điều này có thể giúp bạn tạo mã nhanh hơn rất nhiều - hoặc chỉ là rất nhiều mã phình. Nó tránh được những nhược điểm của sự phản chiếu:

  • mất an toàn kiểu biên dịch
  • lỗi do tái cấu trúc
  • hiệu suất chậm hơn

đã đề cập trước đó.

Nếu sự phản chiếu cảm thấy như gian lận, thì có thể là do bạn dựa trên nhiều phỏng đoán mà bạn không chắc chắn và ruột của bạn đang cảnh báo bạn rằng điều này có rủi ro. Hãy chắc chắn cung cấp một cách để tăng cường siêu dữ liệu vốn có trong sự phản chiếu với siêu dữ liệu của riêng bạn, nơi bạn có thể mô tả tất cả các quirks và trường hợp đặc biệt của các lớp trong thế giới thực mà bạn có thể gặp phải.


2

Nó không phải là gian lận, nhưng giống như bất kỳ công cụ nào, nó nên được sử dụng cho những gì nó dự định giải quyết. Sự phản chiếu, theo định nghĩa, cho phép bạn kiểm tra và sửa đổi mã thông qua mã; nếu đó là những gì bạn cần làm, thì sự phản chiếu là công cụ cho công việc. Phản ánh là tất cả về mã meta: Mã nhắm mục tiêu mã (trái ngược với mã thông thường, nhắm mục tiêu dữ liệu).

Một ví dụ về sử dụng phản xạ tốt là các lớp giao diện dịch vụ web chung: Một thiết kế điển hình là tách biệt việc thực hiện giao thức khỏi chức năng tải trọng. Vì vậy, sau đó bạn có một lớp (hãy gọi nó T) thực hiện tải trọng của bạn và một lớp khác thực hiện giao thức ( P). Tkhá đơn giản: đối với mỗi cuộc gọi bạn muốn thực hiện, chỉ cần viết một phương thức làm bất cứ điều gì đáng lẽ phải làm. Ptuy nhiên, cần ánh xạ các cuộc gọi dịch vụ web đến các cuộc gọi phương thức. Làm cho bản đồ này chung chung là mong muốn, bởi vì nó tránh được sự dư thừa, và làm cho Pcó thể tái sử dụng cao. Reflection cung cấp các phương tiện để kiểm tra lớp Ttrong thời gian chạy và gọi các phương thức của nó dựa trên các chuỗi được truyền Pqua giao thức dịch vụ web, mà không có bất kỳ kiến ​​thức nào về thời gian biên dịch của lớpT. Sử dụng quy tắc 'code about code', người ta có thể lập luận rằng lớp Pcó mã trong lớp Tlà một phần của dữ liệu của nó.

Tuy nhiên.

Sự phản chiếu cũng cung cấp cho bạn các công cụ để khắc phục các hạn chế của hệ thống loại ngôn ngữ - về mặt lý thuyết, bạn có thể chuyển tất cả các tham số dưới dạng loại objectvà gọi các phương thức của chúng thông qua các phản xạ. Voilà, ngôn ngữ được cho là thực thi kỷ luật gõ tĩnh mạnh mẽ hiện hành xử giống như một ngôn ngữ được gõ động với ràng buộc muộn, chỉ có điều cú pháp phức tạp hơn nhiều. Mỗi trường hợp của một mẫu như vậy tôi từng thấy cho đến nay đều là một bản hack bẩn và luôn luôn là một giải pháp trong hệ thống loại ngôn ngữ, và nó sẽ an toàn hơn, thanh lịch hơn và hiệu quả hơn về mọi mặt .

Một vài trường hợp ngoại lệ tồn tại, chẳng hạn như các điều khiển GUI có thể được liên kết dữ liệu với các loại nguồn dữ liệu không liên quan khác nhau; bắt buộc rằng dữ liệu của bạn triển khai một giao diện nhất định chỉ để bạn có thể liên kết dữ liệu không thực tế và lập trình viên cũng không thực hiện bộ điều hợp cho từng loại nguồn dữ liệu. Trong trường hợp này, sử dụng sự phản chiếu để phát hiện loại nguồn dữ liệu và điều chỉnh ràng buộc dữ liệu là một lựa chọn hữu ích hơn.


2

Một vấn đề chúng tôi gặp phải với Reflection là khi chúng tôi thêm Obfuscation vào hỗn hợp. Tất cả các lớp nhận được tên mới và đột nhiên tải một lớp hoặc chức năng bởi tên của nó dừng hoạt động.


1

Nó hoàn toàn phụ thuộc. Một ví dụ về một thứ khó có thể thực hiện nếu không có sự phản chiếu sẽ là sao chép ObjectListView . Nó cũng tạo mã IL một cách nhanh chóng.


1

Phản chiếu là phương pháp chính để tạo ra các hệ thống dựa trên quy ước. Tôi sẽ không ngạc nhiên khi thấy nó được sử dụng nhiều trong hầu hết các khung MVC. Đây là một thành phần chính trong ORM. Rất có thể, bạn đã sử dụng các thành phần được xây dựng với nó mỗi ngày.

Thay thế cho việc sử dụng như vậy là cấu hình, có nhược điểm riêng.


0

Sự phản chiếu có thể đạt được những điều đơn giản là không thể được thực hiện bằng cách khác.

Ví dụ: xem xét cách tối ưu hóa mã này:

int PoorHash(char Operator, int seed, IEnumerable<int> values) {
    foreach (var v in values) {
        seed += 1;
        switch (char) {
            case '+': seed += v; break;
            case '^': seed ^= v; break;
            case '-': seed -= v; break;
            ...
        }
        seed *= 3;
    }
    return seed;
}

Có một cú đánh thử nghiệm đắt tiền ở giữa vòng lặp bên trong, nhưng việc trích xuất nó đòi hỏi phải viết lại vòng lặp một lần cho mỗi toán tử. Sự phản chiếu cho phép chúng ta có được hiệu suất ngang bằng với trích xuất bài kiểm tra đó, mà không lặp lại vòng lặp hàng chục lần (và do đó hy sinh khả năng bảo trì). Chỉ cần tạo và biên dịch vòng lặp bạn cần một cách nhanh chóng.

Tôi thực sự đã thực hiện tối ưu hóa này , mặc dù tình huống phức tạp hơn một chút và kết quả thật đáng kinh ngạc. Một thứ tự cải thiện cường độ trong hiệu suất và ít dòng mã hơn.

(Lưu ý: Ban đầu tôi đã thử tương đương với việc chuyển trong Func thay vì char, và nó tốt hơn một chút, nhưng không đạt được độ phản chiếu gấp 10 lần.)


1
Thay vào đó, tối ưu hóa tốt hơn là vượt qua một functor. Sẽ có khả năng được nội tuyến trong thời gian chạy bởi trình biên dịch JIT và có thể duy trì nhiều hơn so với phản xạ.
Billy ONeal

Điều đó sẽ dễ bảo trì hơn và tôi thực sự đã thử nó trước, nhưng nó không đủ nhanh. JIT chắc chắn không nội tuyến, có lẽ bởi vì trong trường hợp của tôi, có một vòng lặp thứ hai bên trong các hoạt động để thực hiện.
Craig Gidney

Ngoài ra, tôi chỉ ra rằng những gì bạn có ở đó thực sự là mã tự sửa đổi, không thực sự phản ánh. Người ta truy cập nó thông qua các API phản chiếu trong hầu hết các ngôn ngữ hỗ trợ phản chiếu, nhưng nó có thể được thực hiện đơn giản như trong các ngôn ngữ không hỗ trợ phản chiếu (ví dụ: có thể có trong C ++)
Billy ONeal

Tôi muốn tránh ví dụ 'bình đẳng cấu trúc' tiêu chuẩn. Sự phản chiếu là không cần thiết cho mã tự sửa đổi, nhưng nó chắc chắn có ích.
Craig Gidney

Không hẳn vậy. Bạn có thể làm điều đó trong các ngôn ngữ không phản chiếu tốt.
Billy ONeal

-2

Không có cách nào là gian lận ... Thay vào đó, nó trao quyền cho các máy chủ ứng dụng chạy các lớp do người dùng tạo với tên mà họ chọn, do đó cung cấp sự linh hoạt cho người dùng, không lừa dối họ.

Và nếu bạn muốn xem mã của bất kỳ tệp. Class nào (bằng Java) thì có một số trình dịch ngược có sẵn miễn phí!


Dịch ngược không phải là một tính năng phản ánh.
Billy ONeal

vâng, không phải ... Nhưng tôi muốn nói rằng nếu bạn cảm thấy như gian lận trong khi sử dụng sự phản chiếu (cung cấp cho bạn thông tin chi tiết về bất kỳ lớp nào trong java) thì bạn phản ánh bcoz là một khái niệm rất hữu ích và nếu biết chi tiết về bất kỳ lớp là những gì liên quan đến bạn hơn là có thể được thực hiện dễ dàng với bất kỳ trình dịch ngược nào ...
ANSHUL JAIN

2
Phản ánh là một khái niệm hữu ích trong một số trường hợp, vâng. Nhưng 99,9% thời gian tôi thấy nó đang được sử dụng Tôi thấy nó được sử dụng để hack xung quanh một lỗi thiết kế.
Billy ONeal
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.