มีปัญหากับการใช้ Reflection หรือไม่?


49

ฉันไม่รู้ว่าทำไม แต่ฉันมักจะรู้สึกว่าฉัน "โกง" เมื่อฉันใช้การสะท้อน - อาจเป็นเพราะการแสดงที่ฉันรู้ว่าฉันกำลังถ่าย

ส่วนหนึ่งของฉันบอกว่าถ้าเป็นส่วนหนึ่งของภาษาที่คุณใช้และสามารถบรรลุสิ่งที่คุณพยายามจะทำทำไมไม่ลองใช้มัน อีกส่วนหนึ่งของฉันบอกว่าจะต้องมีวิธีที่ฉันสามารถทำได้โดยไม่ต้องใช้การสะท้อน ฉันเดาว่ามันอาจขึ้นอยู่กับสถานการณ์

ปัญหาที่อาจเกิดขึ้นที่ฉันต้องระวังเมื่อใช้การสะท้อนและฉันควรกังวลเกี่ยวกับปัญหาเหล่านี้อย่างไร? ต้องใช้ความพยายามมากแค่ไหนในการลองหาวิธีการแก้ปัญหาแบบเดิม ๆ


2
ฉันเดาว่ามันขึ้นอยู่กับภาษาและสภาพแวดล้อม บางคนสนับสนุนมัน บางครั้งเมื่อทำงานใน Java ฉันต้องการการสนับสนุนที่ดีขึ้น
FrustratedWithFormsDesigner

18
ฉันเดาว่ามันไม่ยากนักที่จะแยกแยะระหว่าง "การสะท้อนการโกง" และการใช้งานที่ถูกต้อง: เมื่อคุณตรวจสอบสมาชิกส่วนตัวหรือใช้เพื่อเรียกวิธีการส่วนตัว เมื่อคุณใช้มันเพื่อโต้ตอบกับประเภทที่คุณไม่มีความรู้เกี่ยวกับมันก็อาจจะตกลง (databinding, proxies ฯลฯ )
เหยี่ยว

1
คุณใช้ภาษาอะไร Brainfuck ไม่มีเงาสะท้อนและ Python แตกต่างกัน
งาน

1
ฉันไม่เคยเข้าใจเลยว่าทำไมจึงอนุญาตให้เข้าถึงวิธีการส่วนตัวผ่านการสะท้อนกลับ ตามสัญชาตญาณของฉันมันควรจะห้าม
Giorgio

3
ยากที่จะเชื่อว่าคำถามที่มีคำพูดไม่ดีนี้มีผู้โหวต 27 คนโดยไม่มีการแก้ไขใด ๆ
Aaronaught

คำตอบ:


48

ไม่มันไม่ใช่การโกงมันเป็นวิธีการแก้ปัญหาในภาษาการเขียนโปรแกรมบางอย่าง

ตอนนี้มันมักจะไม่ใช่ทางออกที่ดีที่สุด (สะอาดที่สุดง่ายที่สุดและง่ายที่สุดในการบำรุงรักษา) หากมีวิธีที่ดีกว่าให้ใช้อันนั้นแน่นอน อย่างไรก็ตามบางครั้งก็ไม่มี หรือถ้ามีมันมีความซับซ้อนมากขึ้นเกี่ยวข้องกับการทำสำเนารหัสจำนวนมาก ฯลฯ ซึ่งทำให้เป็นไปไม่ได้ (ยากที่จะรักษาในระยะยาว)

ตัวอย่างจากโครงการปัจจุบันของเรา (Java):

  • เครื่องมือทดสอบของเราใช้การสะท้อนเพื่อโหลดการกำหนดค่าจากไฟล์ XML คลาสที่จะถูกเตรียมข้อมูลเบื้องต้นมีฟิลด์เฉพาะและตัวโหลดการกำหนดค่าใช้การสะท้อนเพื่อจับคู่องค์ประกอบ XML ที่มีชื่อfieldXกับฟิลด์ที่เหมาะสมในคลาสและเพื่อเริ่มต้นส่วนหลัง ในบางกรณีมันสามารถสร้างกล่องโต้ตอบ GUI อย่างง่ายจากคุณสมบัติที่ระบุได้ทันที หากไม่มีการไตร่ตรองสิ่งนี้จะใช้โค้ดหลายร้อยบรรทัดในหลายแอปพลิเคชัน ดังนั้นการไตร่ตรองจึงช่วยให้เรารวบรวมเครื่องมือง่าย ๆ ได้อย่างรวดเร็วโดยไม่ต้องยุ่งยากมากและทำให้เราสามารถมุ่งเน้นไปที่ส่วนสำคัญ (การทดสอบการถดถอยของแอปพลิเคชันเว็บของเราวิเคราะห์บันทึกเซิร์ฟเวอร์ ฯลฯ ) แทนที่จะไม่เกี่ยวข้อง
  • หนึ่งโมดูลของเว็บแอปดั้งเดิมของเรานั้นหมายถึงการส่งออก / นำเข้าข้อมูลจากตารางฐานข้อมูลไปยังแผ่นงาน Excel และย้อนกลับ มันมีรหัสซ้ำจำนวนมากซึ่งแน่นอนว่าการทำซ้ำไม่เหมือนกันบางส่วนมีข้อบกพร่องอื่น ๆ ด้วยการใช้ภาพสะท้อนวิปัสสนาและคำอธิบายประกอบฉันสามารถกำจัดการทำซ้ำส่วนใหญ่ได้ 5K ถึงต่ำกว่า 2.4K ในขณะที่ทำให้รหัสแข็งแกร่งขึ้นและง่ายต่อการบำรุงรักษาหรือขยาย ตอนนี้โมดูลดังกล่าวไม่ได้เป็นปัญหาสำหรับเรา - ด้วยการใช้การไตร่ตรองอย่างรอบคอบ

บรรทัดล่างคือเช่นเครื่องมือที่มีประสิทธิภาพใด ๆ การสะท้อนก็สามารถนำมาใช้เพื่อยิงตัวเองในเท้า หากคุณเรียนรู้ว่าจะใช้เมื่อไรและอย่างไร (ไม่) จะสามารถนำวิธีการแก้ปัญหาที่สง่างามและสะอาดมาสู่ปัญหาที่ยากได้ หากคุณใช้งานในทางที่ผิดคุณสามารถเปลี่ยนปัญหาง่าย ๆ ให้กลายเป็นเรื่องซับซ้อนและน่าเกลียด


8
+1 Reflection มีประโยชน์อย่างมากสำหรับการนำเข้า / ส่งออกข้อมูลเมื่อคุณมีวัตถุระดับกลางสำหรับเหตุผลการแปลง
Ed James

2
นอกจากนี้ยังมีประโยชน์อย่างมากในแอพที่ขับเคลื่อนด้วยข้อมูลแทนที่จะใช้สแต็คจำนวนมากif (propName = n) setN(propValue);คุณสามารถตั้งชื่อแท็ก XML (เช่น) แท็กเหมือนกับคุณสมบัติรหัสของคุณและเรียกใช้วนรอบ วิธีนี้ยังทำให้การเพิ่มคุณสมบัติในภายหลังทำได้ง่ายขึ้น
Michael K

การสะท้อนกลับถูกใช้อย่างมากในอินเทอร์เฟซ Fluent เช่น FluentNHibernate
Scott Whitlock

4
@Michael: จนกว่าคุณจะตัดสินใจเปลี่ยนชื่อหนึ่งในคุณสมบัติเหล่านั้นในคลาสและพบว่าโค้ดของคุณระเบิด หากคุณไม่จำเป็นต้องรักษาความสามารถในการเปรียบเทียบกับสิ่งที่โปรแกรมของคุณสร้างขึ้นมันก็ใช้ได้ แต่ฉันคิดว่ามันไม่ใช่พวกเราส่วนใหญ่
Billy ONeal

1
@Billy ฉันไม่ได้ตั้งใจจะโต้แย้งคุณฉันเห็นด้วยกับสิ่งที่คุณเขียน ถึงแม้ว่าตัวอย่างที่คุณนำมาเป็น IMHO ย่อยของกฎทั่วไป "หลีกเลี่ยงการเปลี่ยนส่วนต่อประสานสาธารณะ"
PéterTörök

37

มันไม่ได้โกง แต่โดยปกติจะเป็นความคิดที่ไม่ดีในรหัสการผลิตอย่างน้อยด้วยเหตุผลดังต่อไปนี้:

  • คุณสูญเสียความปลอดภัยประเภทการคอมไพล์เวลา - เป็นประโยชน์ในการตรวจสอบคอมไพเลอร์ว่ามีวิธีการในเวลารวบรวม หากคุณใช้การไตร่ตรองคุณจะได้รับข้อผิดพลาดขณะทำงานซึ่งอาจส่งผลกระทบต่อผู้ใช้ปลายทางหากคุณทดสอบไม่ดีพอ แม้ว่าคุณจะตรวจพบข้อผิดพลาดมันจะยากต่อการตรวจแก้จุดบกพร่อง
  • มันทำให้เกิดข้อผิดพลาดเมื่อ refactoring - ถ้าคุณเข้าถึงสมาชิกตามชื่อของมัน (เช่นการใช้สตริงที่มีการเข้ารหัสยาก) สิ่งนี้จะไม่ได้รับการเปลี่ยนแปลงจากเครื่องมือ refactoring code ส่วนใหญ่และคุณจะมีข้อผิดพลาดทันทีซึ่งอาจจะค่อนข้าง ยากที่จะติดตาม
  • ประสิทธิภาพการทำงานจะช้าลง - การสะท้อนที่รันไทม์จะช้ากว่าการเรียกวิธี / การค้นหาตัวแปรที่คอมไพล์แบบคงที่ หากคุณกำลังทำการไตร่ตรองเป็นครั้งคราวมันจะไม่สำคัญ แต่สิ่งนี้อาจกลายเป็นคอขวดของประสิทธิภาพในกรณีที่คุณทำการโทรผ่านการสะท้อนหลายพันหรือล้านครั้งต่อวินาที ฉันเคยได้รับความเร็ว 10x ในโค้ด Clojure บางตัวเพียงกำจัดการสะท้อนทั้งหมดดังนั้นใช่นี่เป็นปัญหาจริง

ฉันขอแนะนำให้ จำกัด การใช้การสะท้อนกลับในกรณีต่อไปนี้:

  • สำหรับการสร้างต้นแบบอย่างรวดเร็วหรือรหัส "throwaway" เมื่อเป็นโซลูชันที่ง่ายที่สุด
  • สำหรับกรณีการใช้งานการสะท้อนที่แท้จริงเช่นการใช้เครื่องมือ IDE ที่ให้ผู้ใช้สามารถตรวจสอบฟิลด์ / วิธีการของวัตถุที่กำหนดเองได้ที่รันไทม์

ในกรณีอื่น ๆ ทั้งหมดฉันขอแนะนำให้หาวิธีที่หลีกเลี่ยงการสะท้อน การกำหนดอินเทอร์เฟซด้วยวิธีการที่เหมาะสมและนำไปใช้กับชุดของคลาสที่คุณต้องการเรียกใช้เมธอดที่มักจะเพียงพอที่จะแก้ปัญหากรณีที่ง่ายที่สุด


3
+1 - มีหลายกรณีที่ใช้ในการสะท้อน แต่ส่วนใหญ่ฉันเห็นโปรแกรมเมอร์ใช้มันเป็นกระดาษมากกว่าการออกแบบที่มีข้อบกพร่องร้ายแรง กำหนดอินเตอร์เฟสและพยายามลบการพึ่งพาการสะท้อน เช่นเดียวกับ GOTO มันมีประโยชน์ แต่ส่วนใหญ่ไม่ดี (บางคนก็ดีแน่นอน)
Billy ONeal

3
โปรดจำไว้ว่าประเด็นข้างต้นอาจนำไปใช้กับภาษาที่คุณโปรดปราน ยกตัวอย่างเช่นการไตร่ตรองนั้นไม่มีโทษอย่างรวดเร็วใน Smalltalk และคุณจะไม่สูญเสียความปลอดภัยในการคอมไพล์เวลาเนื่องจากการคำนวณนั้นถูกผูกมัดทั้งหมด
Frank Shearar

การสะท้อนใน D ไม่มีข้อเสียเปรียบที่คุณพูดถึง ดังนั้นฉันขอยืนยันว่าคุณโทษการใช้งานในบางภาษามากกว่าที่จะเลือกใหม่ ฉันไม่ค่อยรู้เรื่อง smalltalk มากนัก แต่ตาม @Frank Shearar มันก็ไม่มีข้อเสียเปรียบเช่นกัน
deadalnix

2
@deadalinx: คุณอ้างถึงข้อเสียแบบไหน? มีหลายคำตอบในนี้ ปัญหาด้านประสิทธิภาพเป็นสิ่งเดียวที่ขึ้นอยู่กับภาษา
Billy ONeal

1
ฉันควรเพิ่มว่าประเด็นที่สอง - ข้อบกพร่องที่เกิดขึ้นในระหว่างการเปลี่ยนโครงสร้าง - อาจเป็นเรื่องที่ร้ายแรงที่สุด โดยเฉพาะอย่างยิ่งการพึ่งพาสิ่งที่มีชื่อแตกตัวทันทีเมื่อมีการเปลี่ยนแปลงชื่อของสิ่งนั้น ข้อผิดพลาดที่เกิดขึ้นอาจน้อยกว่าข้อมูลเว้นแต่คุณจะระวังให้ดี
Frank Shearar

11

Reflection เป็นเพียงรูปแบบหนึ่งของการเขียนโปรแกรมเมตาและใช้ได้เช่นเดียวกับพารามิเตอร์ประเภทที่คุณเห็นในภาษาส่วนใหญ่ในปัจจุบัน การสะท้อนกลับเป็นโปรแกรมที่ทรงพลังและทั่วไปและโปรแกรมไตร่ตรองนั้นมีความสามารถในการบำรุงรักษาสูง (เมื่อใช้อย่างถูกต้องแน่นอน) และอื่น ๆ มากกว่าโปรแกรมเชิงวัตถุหรือกระบวนการเชิงวัตถุ ใช่คุณจ่ายราคาตามประสิทธิภาพ - แต่ฉันยินดีที่จะให้โปรแกรมที่ช้ากว่าซึ่งสามารถดูแลรักษาได้ดีขึ้นในหลาย ๆ กรณีหรือมากที่สุด


2
+1 สิ่งนี้ช่วยให้ฉันเข้าใจว่าภาพสะท้อนคืออะไร ฉันเป็นโปรแกรมเมอร์ C ++ และดังนั้นฉันจึงไม่เคยพลาดการสะท้อน สิ่งนี้ช่วยได้ (แม้ว่าฉันจะสารภาพว่าจากมุมมองของฉัน Reflection ดูเหมือนจะเป็นความพยายามในการกระทบยอดข้อบกพร่องในภาษาเรา C ++ พวกใช้เทมเพลตสำหรับเรื่องนั้นดังนั้นฉันคิดว่าคุณสามารถพูดแบบนั้น :)
greyfade

4
เรื่องประสิทธิภาพ - ในบางกรณีคุณสามารถใช้ reflect API เพื่อเขียนรหัสประสิทธิภาพกลับคืนได้อย่างสมบูรณ์ ตัวอย่างเช่นใน. NET คุณสามารถเขียน IL ลงในแอปปัจจุบันได้ดังนั้นโค้ด "reflect" ของคุณจึงเร็วพอ ๆ กับโค้ดอื่น ๆ (ยกเว้นคุณสามารถลบ if / else / any จำนวนมากออกไปได้ คิดออกกฎที่แน่นอน)
Marc Gravell

@greyfade: ในแง่หนึ่งแม่แบบกำลังทำการสะท้อนเวลาแบบคอมไพล์เท่านั้น ความสามารถในการทำงานที่รันไทม์มีข้อดีของการอนุญาตให้สร้างความสามารถที่มีประสิทธิภาพในแอปพลิเคชันโดยไม่ต้องคอมไพล์ใหม่ คุณแลกเปลี่ยนประสิทธิภาพเพื่อความยืดหยุ่นซึ่งเป็นการแลกเปลี่ยนที่ยอมรับได้มากกว่าเวลาที่คุณคาดหวัง (จากพื้นหลัง C ++ ของคุณ)
Donal Fellows

ฉันไม่เข้าใจคำตอบของคุณ ดูเหมือนว่าคุณจะบอกว่าโปรแกรมที่ใช้สะท้อนมีมากขึ้นการบำรุงรักษากว่าผู้ที่ไม่ได้เช่นถ้าสะท้อนเป็นรูปแบบการเขียนโปรแกรมที่เหนือกว่าที่ควรจะมาแทนที่โปรแกรมเชิงวัตถุและขั้นตอนการปฏิบัติงานหากไม่จำเป็น
DavidS

8

แน่นอนมันทั้งหมดขึ้นอยู่กับสิ่งที่คุณพยายามบรรลุ

ตัวอย่างเช่นฉันเขียนแอปพลิเคชันตัวตรวจสอบสื่อที่ใช้การฉีดอ้างอิงเพื่อกำหนดประเภทของสื่อ (ไฟล์ MP3 หรือไฟล์ JPEG) เพื่อตรวจสอบ เชลล์จำเป็นต้องแสดงกริดที่มีข้อมูลที่เกี่ยวข้องสำหรับแต่ละประเภท แต่ไม่มีความรู้เกี่ยวกับสิ่งที่จะแสดง สิ่งนี้กำหนดไว้ในชุดประกอบที่อ่านสื่อประเภทนั้น

ดังนั้นฉันจึงต้องใช้การสะท้อนเพื่อให้ได้จำนวนคอลัมน์ที่จะแสดงและประเภทและชื่อของมันเพื่อที่ฉันจะได้ตั้งค่ากริดได้อย่างถูกต้อง นอกจากนี้ยังหมายความว่าฉันสามารถอัปเดตไลบรารีที่ถูกฉีด (หรือสร้างใหม่) โดยไม่ต้องเปลี่ยนรหัสหรือไฟล์การกำหนดค่าอื่น ๆ

วิธีเดียวที่จะมีไฟล์การกำหนดค่าที่จะต้องมีการปรับปรุงเมื่อฉันเปลี่ยนประเภทของสื่อที่ถูกตรวจสอบ นี่จะเป็นการแนะนำจุดที่ล้มเหลวของแอปพลิเคชัน


1
"แน่นอนมันทั้งหมดขึ้นอยู่กับสิ่งที่คุณพยายามบรรลุ" +1
DaveShaw

7

Reflection เป็นเครื่องมือที่ยอดเยี่ยมหากคุณเป็นผู้แต่งห้องสมุดและไม่มีอิทธิพลต่อข้อมูลที่เข้ามา การรวมกันของการสะท้อนและการเขียนโปรแกรมเมตาสามารถช่วยให้ห้องสมุดของคุณทำงานได้อย่างราบรื่นกับผู้โทรเข้าโดยไม่จำเป็นต้องข้ามผ่านการสร้างรหัสเป็นต้น

ฉันพยายามกีดกันการสะท้อนกลับในรหัสแอปพลิเคชัน ที่เลเยอร์แอปคุณควรใช้คำอุปมาอุปมัยที่แตกต่างกัน - อินเตอร์เฟส, abstraction, encapsulation เป็นต้น


ห้องสมุดดังกล่าวมักใช้งานยากและหลีกเลี่ยงได้ดีที่สุด (เช่นฤดูใบไม้ผลิ)
Sridhar Sarnobat

@Sridhar ดังนั้นคุณไม่เคยใช้ API การทำให้เป็นอันดับหรือไม่ หรือ ORM / micro-ORM ใด ๆ
Marc Gravell

ฉันใช้มันโดยไม่เลือกเอง มันเป็นการทำลายศีลธรรมไปสู่ปัญหาที่ฉันหลีกเลี่ยงได้หากฉันไม่ได้รับคำสั่งให้ทำ
Sridhar Sarnobat

7

Reflection นั้นยอดเยี่ยมสำหรับการสร้างเครื่องมือสำหรับนักพัฒนา

เนื่องจากช่วยให้สภาพแวดล้อมการสร้างของคุณตรวจสอบรหัสและอาจสร้างเครื่องมือที่ถูกต้องเพื่อจัดการ / เริ่มตรวจสอบรหัส

ในฐานะที่เป็นเทคนิคการเขียนโปรแกรมทั่วไปจะมีประโยชน์ แต่เปราะบางกว่าที่คนส่วนใหญ่จินตนาการ

หนึ่งในการพัฒนาที่ใช้สำหรับการไตร่ตรอง (IMO) ก็คือมันทำให้การเขียนไลบรารีการสตรีมทั่วไปเป็นเรื่องง่ายมาก (ตราบใดที่คำอธิบายคลาสของคุณไม่เคยเปลี่ยนแปลง


แน่นอนว่าฤดูใบไม้ผลินั้น "เปราะกว่าที่คนส่วนใหญ่จินตนาการ"
Sridhar Sarnobat

5

การใช้การไตร่ตรองมักเป็นอันตรายในภาษา OO หากไม่ได้ใช้ด้วยความตระหนักดี

ฉันสูญเสียการนับจำนวนคำถามที่ไม่ดีที่ฉันเคยเห็นในเว็บไซต์ StackExchange ที่

  1. ภาษาที่ใช้คือ OO
  2. ผู้เขียนต้องการค้นหาประเภทของวัตถุที่ถูกส่งผ่านแล้วเรียกวิธีการอย่างใดอย่างหนึ่ง
  3. ผู้เขียนปฏิเสธที่จะยอมรับการสะท้อนกลับว่าเป็นเทคนิคที่ไม่ถูกต้องและกล่าวหาว่าใครก็ตามที่ชี้ให้เห็นว่า "ไม่รู้วิธีช่วยฉัน"

นี่ คือตัวอย่างทั่วไป

จุดสำคัญที่สุดของ OO คือ

  1. คุณจัดกลุ่มฟังก์ชั่นที่รู้วิธีจัดการโครงสร้าง / แนวคิดด้วยตัวของมันเอง
  2. ในจุดใดของรหัสของคุณคุณควรรู้มากพอเกี่ยวกับประเภทของวัตถุที่จะรู้ว่ามันมีฟังก์ชั่นที่เกี่ยวข้องและขอให้มันเรียกรุ่นเฉพาะของฟังก์ชั่นเหล่านั้น
  3. คุณรับรองความจริงของประเด็นก่อนหน้านี้โดยการระบุประเภทอินพุตที่ถูกต้องสำหรับทุกฟังก์ชั่นและให้แต่ละฟังก์ชั่นไม่รู้จัก (และไม่ต้องทำมากไปกว่าที่เกี่ยวข้อง)

หาก ณ จุดใดในรหัสของคุณจุดที่ 2 ไม่ถูกต้องสำหรับวัตถุที่คุณได้ผ่านไปแล้วหนึ่งในนั้นเป็นจริง

  1. อินพุตที่ป้อนไม่ถูกต้อง
  2. รหัสของคุณมีโครงสร้างไม่ดี
  3. คุณไม่รู้ว่าคุณกำลังทำอะไรอยู่

นักพัฒนาที่มีทักษะต่ำเพียงไม่ได้สิ่งนี้และเชื่อว่าพวกเขาสามารถส่งผ่านอะไรก็ได้ในส่วนใด ๆ ของรหัสและทำสิ่งที่พวกเขาต้องการจากชุดของความเป็นไปได้ โง่เหล่านี้สะท้อนให้เห็นถึงการใช้เป็นจำนวนมาก

สำหรับภาษา OO จำเป็นต้องมีการไตร่ตรองในกิจกรรมเมตาดาต้า (คลาสโหลดเดอร์, การฉีดพึ่งพา) ในบริบทเหล่านั้นจำเป็นต้องมีการไตร่ตรองเนื่องจากคุณกำลังให้บริการทั่วไปเพื่อช่วยในการจัดการ / กำหนดค่าของโค้ดซึ่งคุณไม่รู้อะไรเลยด้วยเหตุผลที่ดีและถูกต้องตามกฎหมาย ในเกือบทุกสถานการณ์อื่น ๆ หากคุณเอื้อมถึงการไตร่ตรองแล้วคุณกำลังทำอะไรผิดพลาดและคุณต้องถามตัวเองว่าทำไมชิ้นส่วนของรหัสนี้จึงไม่พอรู้เกี่ยวกับวัตถุที่ผ่านไปแล้ว


3

อีกทางเลือกหนึ่งในกรณีที่โดเมนของคลาสที่มีการสะท้อนดีถูกกำหนดให้ใช้การสะท้อนพร้อมกับข้อมูลเมตาอื่น ๆเพื่อสร้างรหัสแทนที่จะใช้การสะท้อนที่รันไทม์ ฉันทำสิ่งนี้โดยใช้ FreeMarker / FMPP; มีเครื่องมืออื่น ๆ ให้เลือกมากมาย ข้อดีของการทำเช่นนี้คือคุณจะได้รับรหัส "ของจริง" ที่สามารถบั๊กได้ง่ายและอื่น ๆ

ขึ้นอยู่กับสถานการณ์สิ่งนี้สามารถช่วยให้คุณสร้างรหัสได้เร็วขึ้นมากหรือเป็นจำนวนมากของรหัส มันหลีกเลี่ยงข้อเสียของการสะท้อน:

  • การสูญเสียความปลอดภัยประเภทเวลารวบรวม
  • ข้อผิดพลาดเนื่องจากการ refactoring
  • ประสิทธิภาพการทำงานช้าลง

กล่าวถึงก่อนหน้านี้

หากการสะท้อนความรู้สึกรู้สึกว่ามีการโกงอาจเป็นเพราะคุณกำลังคาดเดากับสิ่งที่คุณไม่แน่ใจและลำไส้ของคุณเตือนคุณว่าสิ่งนี้มีความเสี่ยง ตรวจสอบให้แน่ใจว่าได้เตรียมวิธีในการปรับปรุงข้อมูลเมตาที่สะท้อนกับเมทาดาทาของคุณเองซึ่งคุณสามารถอธิบายนิสัยและกรณีพิเศษของคลาสโลกแห่งความจริงที่คุณอาจพบ


2

มันไม่ได้โกง แต่ก็เหมือนกับเครื่องมือใด ๆ มันควรจะใช้สำหรับสิ่งที่มันตั้งใจจะแก้ การสะท้อนตามนิยามอนุญาตให้คุณตรวจสอบและแก้ไขโค้ดผ่านโค้ด ถ้านั่นคือสิ่งที่คุณต้องทำการไตร่ตรองก็เป็นเครื่องมือสำหรับงานนั้น การสะท้อนนั้นเป็นข้อมูลเกี่ยวกับ meta-code: รหัสที่เป็นรหัสเป้าหมาย (ตรงข้ามกับรหัสปกติซึ่งมีเป้าหมายเป็นข้อมูล)

ตัวอย่างของการใช้การสะท้อนที่ดีคือคลาสอินเตอร์เฟสของเว็บเซอร์วิสทั่วไป: การออกแบบทั่วไปคือการแยกโพรโทคอลที่แยกออกจากการทำงานของเพย์โหลด ดังนั้นคุณมีคลาสหนึ่ง (ลองเรียกมันTว่า) ที่จะทำ payload ของคุณและอีกอันที่ใช้โปรโตคอล ( P) Tค่อนข้างตรงไปตรงมา: สำหรับการโทรทุกครั้งที่คุณต้องการเพียงเขียนวิธีการหนึ่งที่ทำทุกอย่างที่ควรทำ Pอย่างไรก็ตามต้องจับคู่การบริการบนเว็บกับวิธีการโทร การทำแผนที่ทั่วไปนี้เป็นสิ่งที่ต้องการเพราะมันหลีกเลี่ยงความซ้ำซ้อนและทำให้Pสามารถนำมาใช้ซ้ำได้ Reflection จัดให้มีวิธีการตรวจสอบคลาสTที่รันไทม์และเรียกใช้เมธอดตามสตริงที่ส่งPผ่านโปรโตคอลเว็บเซอร์วิสโดยไม่มีความรู้รวบรวมเวลาของคลาสT. การใช้กฎ 'code about code' เราสามารถอ้างได้ว่าคลาสPนั้นมีโค้ดในคลาสTเป็นส่วนหนึ่งของข้อมูล

อย่างไรก็ตาม

รีเฟลคชั่นยังให้เครื่องมือในการแก้ไขข้อ จำกัด ของระบบประเภทภาษา - ในทางทฤษฎีคุณสามารถส่งพารามิเตอร์ทั้งหมดเป็นประเภทobjectและเรียกวิธีการของพวกเขาผ่านการสะท้อน ตอนนี้, ภาษาที่ควรจะบังคับใช้วินัยการพิมพ์แบบคงที่ที่แข็งแกร่งในขณะนี้ทำงานเหมือนภาษาที่พิมพ์แบบไดนามิกที่มีการผูกปลาย, เฉพาะที่ไวยากรณ์มีความซับซ้อนมากขึ้น ทุกอินสแตนซ์เดียวของรูปแบบดังกล่าวที่ฉันเห็นมานั้นเคยเป็นแฮ็คที่สกปรกและคงเส้นคงวาวิธีแก้ปัญหาภายในระบบภาษาของภาษาจะเป็นไปได้ .

มีข้อยกเว้นบางประการเช่นตัวควบคุม GUI ที่สามารถผูกข้อมูลกับแหล่งข้อมูลประเภทต่างๆที่ไม่เกี่ยวข้อง บังคับให้ข้อมูลของคุณใช้อินเทอร์เฟซบางตัวเพียงเพื่อให้คุณสามารถผูกข้อมูลมันไม่เหมือนจริงและไม่ได้ให้โปรแกรมเมอร์ใช้อะแดปเตอร์สำหรับแหล่งข้อมูลแต่ละประเภท ในกรณีนี้การใช้การสะท้อนเพื่อตรวจจับชนิดของแหล่งข้อมูลและการปรับการเชื่อมโยงข้อมูลเป็นตัวเลือกที่มีประโยชน์มากขึ้น


2

ปัญหาหนึ่งที่เรามีกับ Reflection คือเมื่อเราเพิ่มObfuscationให้กับส่วนผสม คลาสทั้งหมดได้ชื่อใหม่และการโหลดคลาสหรือฟังก์ชันโดยชื่อหยุดทำงานทันที


1

มันขึ้นอยู่กับ ตัวอย่างของสิ่งที่จะยากที่จะทำโดยการสะท้อนจะทำซ้ำObjectListView นอกจากนี้ยังสร้างรหัส IL ได้ทันที


1

การสะท้อนกลับเป็นวิธีการหลักในการสร้างระบบตามหลักการประชุม ฉันจะไม่แปลกใจที่พบว่ามีการใช้งานอย่างหนักในกรอบ MVC ส่วนใหญ่ มันเป็นองค์ประกอบสำคัญใน ORMs โอกาสที่คุณจะได้ใช้ส่วนประกอบที่สร้างขึ้นมาทุกวัน

ทางเลือกสำหรับการใช้เช่นนี้คือการกำหนดค่าซึ่งมีชุดของข้อเสีย


0

การสะท้อนกลับสามารถบรรลุสิ่งที่ไม่สามารถทำได้ในทางปฏิบัติ

ตัวอย่างเช่นพิจารณาวิธีเพิ่มประสิทธิภาพโค้ดนี้:

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;
}

มีการทดสอบการตีที่มีราคาแพงในช่วงกลางของวงใน แต่การแยกมันจำเป็นต้องเขียนวนซ้ำหนึ่งครั้งสำหรับผู้ปฏิบัติงานแต่ละคน การสะท้อนกลับช่วยให้เราสามารถทำงานได้อย่างมีประสิทธิภาพด้วยการแยกการทดสอบนั้นโดยไม่ต้องวนซ้ำซ้ำไปซ้ำมานับสิบครั้ง เพียงแค่สร้างและรวบรวมวงที่คุณต้องการได้ทันที

ฉันได้ทำการปรับให้เหมาะสมนี้จริงแล้วแม้ว่ามันจะซับซ้อนขึ้นเล็กน้อยกับสถานการณ์และผลลัพธ์ก็น่าทึ่ง ลำดับการปรับปรุงประสิทธิภาพในการทำงานและจำนวนบรรทัดที่น้อยลง

(หมายเหตุ: ตอนแรกฉันพยายามเทียบเท่ากับการผ่านใน Func แทนที่จะเป็นตัวละครและมันก็ดีขึ้นเล็กน้อย แต่ไม่ถึงการสะท้อน 10 เท่าที่ทำได้)


1
การเพิ่มประสิทธิภาพที่ดีกว่าคือการส่งนักแสดงแทน มีแนวโน้มที่จะได้รับการอินไลน์ที่รันไทม์โดยคอมไพเลอร์ JIT และสามารถบำรุงรักษาได้ดีกว่าการสะท้อนกลับ
Billy ONeal

นั่นจะบำรุงรักษาได้มากกว่าและฉันลองก่อนจริง ๆ แต่มันไม่เร็วพอ JIT ไม่ได้ทำอินไลน์อย่างแน่นอนอาจเป็นเพราะในกรณีของฉันมีวงวนภายในที่สองมากกว่าการดำเนินการที่จะดำเนินการ
Craig Gidney

นอกจากนี้ฉันชี้ให้เห็นว่าสิ่งที่คุณได้รับคือการแก้ไขโค้ดด้วยตนเองซึ่งไม่ได้สะท้อนออกมาจริงๆ หนึ่งเข้าถึงมันผ่าน API การสะท้อนกลับในภาษาส่วนใหญ่ที่สนับสนุนการสะท้อนกลับ แต่มันสามารถทำได้เช่นเดียวกับในภาษาที่ไม่สนับสนุนการสะท้อน (เช่นมันจะเป็นไปได้ใน C ++)
Billy ONeal

ฉันต้องการหลีกเลี่ยงตัวอย่าง 'ความเท่าเทียมกันทางโครงสร้าง' มาตรฐาน การสะท้อนกลับไม่จำเป็นสำหรับรหัสการแก้ไขตัวเอง แต่ช่วยได้อย่างแน่นอน
Craig Gidney

ไม่ได้จริงๆ คุณสามารถทำได้ในภาษาที่ไม่ใช่ภาพสะท้อนได้ดี
Billy ONeal

-2

ไม่มีทางที่มันจะโกง ... แต่มันให้อำนาจแอพพลิเคชั่นเซิร์ฟเวอร์ในการรันคลาสที่สร้างโดยผู้ใช้ที่มีชื่อตัวเลือกของพวกเขาดังนั้นจึงให้ความยืดหยุ่นแก่ผู้ใช้ไม่ใช่การโกงพวกเขา

และถ้าคุณต้องการที่จะเห็นรหัสของไฟล์. class (ใน Java) ก็มีตัวถอดรหัสหลายตัวให้ใช้งานฟรี!


การแยกส่วนประกอบไม่ใช่คุณสมบัติการสะท้อนกลับ
Billy ONeal

ใช่มันไม่ใช่ ... แต่ฉันหมายถึงว่าถ้าคุณรู้สึกว่าโกงในขณะที่ใช้การสะท้อน (ซึ่งให้รายละเอียดของคลาสใด ๆ ในจาวา) กว่าที่คุณคิดผิด bcoz การสะท้อนกลับเป็นแนวคิดที่มีประโยชน์มากและหากได้รับรายละเอียดใด ๆ ระดับคือสิ่งที่เกี่ยวกับคุณมากกว่าที่สามารถทำได้อย่างง่ายดายด้วย Decompiler ใด ๆ ...
Anshul JAIN

2
Reflection เป็นแนวคิดที่มีประโยชน์ในบางกรณีใช่ แต่ 99.9% ของเวลาที่ฉันเห็นมันถูกใช้ฉันเห็นว่ามันใช้เพื่อการแฮ็กข้อผิดพลาดการออกแบบ
Billy ONeal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.