เหตุใดโมดูล. NET จึงแยกชื่อไฟล์โมดูลออกจากเนมสเปซ


9

ในการปรับใช้ภาษาการเขียนโปรแกรม Scheme (มาตรฐาน R6RS) ฉันสามารถนำเข้าโมดูลดังต่อไปนี้:

(import (abc def xyz))

ระบบจะพยายามค้นหาไฟล์$DIR/abc/def/xyz.slsที่$DIRมีไดเรกทอรีซึ่งคุณเก็บโมดูล Scheme ของคุณไว้ xyz.slsเป็นซอร์สโค้ดสำหรับโมดูลและถูกคอมไพล์อย่างรวดเร็วหากจำเป็น

ระบบโมดูล Ruby, Python และ Perl นั้นคล้ายกันในส่วนนี้

ในทางกลับกัน C # นั้นเกี่ยวข้องกับอีกเล็กน้อย

ก่อนอื่นคุณมีไฟล์ dll ที่คุณต้องอ้างอิงตามโปรเจ็กต์ คุณต้องอ้างอิงแต่ละอย่างชัดเจน สิ่งนี้เกี่ยวข้องมากกว่าการพูดวางไฟล์ dll ในไดเรกทอรีและให้ C # เลือกพวกเขาตามชื่อ

ประการที่สองไม่มีการตั้งชื่อการติดต่อแบบหนึ่งต่อหนึ่งระหว่างชื่อไฟล์ dll และเนมสเปซที่นำเสนอโดย dll ฉันสามารถชื่นชมความยืดหยุ่นนี้ แต่ก็สามารถออกไปจากมือ (และมี)

เพื่อให้เป็นรูปธรรมมันจะดีถ้าเมื่อฉันพูดแบบนี้using abc.def.xyz;C # จะพยายามค้นหาไฟล์abc/def/xyz.dllในบางไดเรกทอรีที่ C # รู้ที่จะดู (กำหนดค่าได้ตามโครงการ)

ฉันพบว่า Ruby, Python, Perl, Scheme มีวิธีการจัดการโมดูลที่สวยงามกว่า ดูเหมือนว่าภาษาที่เกิดขึ้นใหม่มีแนวโน้มที่จะไปด้วยการออกแบบที่เรียบง่าย

ทำไม. NET / C # world ทำสิ่งต่าง ๆ ในลักษณะนี้โดยมีการเพิ่มระดับทางอ้อม


10
กลไกการแก้ปัญหาการประกอบและการจำแนกระดับของ. NET ทำงานได้ดีมานานกว่า 10 ปี ฉันคิดว่าคุณขาดความเข้าใจผิดขั้นพื้นฐาน (หรือมีงานวิจัยไม่เพียงพอ) เกี่ยวกับสาเหตุที่ออกแบบมา - เช่นเพื่อสนับสนุนการเปลี่ยนเส้นทางการชุมนุม ฯลฯ ในเวลาผูกและกลไกการแก้ปัญหาที่มีประโยชน์อื่น ๆ อีกมากมาย
Kev

ฉันค่อนข้างมั่นใจว่าความละเอียดของ DLL จากคำสั่งการใช้จะทำให้การดำเนินการแบบคู่ขนาน นอกจากนี้หากมี 1 ต่อ 1 คุณจะต้องมี 50 DLLs สำหรับ namespaces ทั้งหมดใน mscorlib หรือพวกเขาต้องการที่จะวางแนวคิดของ namespaces
Conrad Frix

อีกระดับของการอ้อม? Hmmmmm .... dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/Spi07g.html
user541686

@gilles ขอบคุณสำหรับการแก้ไขและปรับปรุงคำถาม!
dharmatech

คะแนนของคุณบางอย่างแปลกประหลาดกับ Visual Studio และการเปรียบเทียบกับภาษานั้นค่อนข้างไม่ยุติธรรม ( เช่นการอ้างอิง DLL ในโครงการ) การเปรียบเทียบที่ดีกว่าสำหรับสภาพแวดล้อม. NET แบบเต็มคือ Java + Eclipse
Ross Patterson

คำตอบ:


22

คำอธิบายประกอบต่อไปนี้ในส่วนคำแนะนำการออกแบบกรอบ 3.3 ชื่อของแอสเซมบลีและที่อยู่ให้ข้อมูลเชิงลึกว่าทำไมเนมสเปซและแอสเซมบลีแยกกัน

BRAD ABRAMS ในช่วงต้นของการออกแบบ CLR เราตัดสินใจแยกมุมมองนักพัฒนาของแพลตฟอร์ม (เนมสเปซ) ออกจากมุมมองของบรรจุภัณฑ์และการปรับใช้ของแพลตฟอร์ม (ชุดประกอบ) การแยกนี้อนุญาตให้แต่ละการปรับให้เหมาะสมอย่างอิสระตามเกณฑ์ของตนเอง ตัวอย่างเช่นเรามีอิสระที่จะแยกเนมสเปซออกเป็นกลุ่มที่เกี่ยวข้องกับหน้าที่ (เช่น I / O ทุกอย่างใน System.IO) ในขณะที่แอสเซมบลีสามารถนำมาประกอบเพื่อประสิทธิภาพ (ความเร็วในการโหลด), การใช้งาน, การบริการ .


ดูเหมือนว่าแหล่งข้อมูลที่เชื่อถือได้มากที่สุดจนถึงตอนนี้ ขอบคุณคอนราด!
dharmatech

+1 สำหรับการรับคำตอบที่น่าเชื่อถือ แต่ยังทุกคำถาม " ทำไม C # ทำ <X> " ก็ต้องดูผ่านเลนส์ของ " Java ทำ <X> ดังนี้: ... " เพราะ C # เป็น (ชัดเจนหรือไม่) ปฏิกิริยาของ Sun และ วาระการทำงานที่แตกต่างของ Microsoft สำหรับ Java บน Windows
Ross Patterson

6

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

หนึ่งเนมสเปซไลบรารีหลายรายการ:

ข้อดีอย่างหนึ่งคือฉันสามารถแทนที่ห้องสมุดอื่นได้อย่างง่ายดาย สมมติว่าฉันมีเนมสเปซMyCompany.MyApplication.DALและห้องสมุดDAL.MicrosoftSQL.dllซึ่งมีแบบสอบถาม SQL ทั้งหมดและสิ่งอื่น ๆ ซึ่งอาจเฉพาะกับฐานข้อมูล ถ้าฉันต้องการให้แอพพลิเคชั่นเข้ากันได้กับ Oracle ฉันแค่เพิ่มDAL.Oracle.dllโดยรักษาเนมสเปซเดียวกัน จากนี้ไปฉันสามารถส่งมอบแอปพลิเคชั่นด้วยห้องสมุดแห่งหนึ่งสำหรับลูกค้าที่ต้องการความเข้ากันได้กับ Microsoft SQL Server และห้องสมุดอื่น ๆ สำหรับลูกค้าที่ใช้ Oracle

การเปลี่ยนเนมสเปซในระดับนี้จะนำไปสู่รหัสที่ซ้ำกันหรือความจำเป็นในการไปและเปลี่ยนusings ทั้งหมดภายในซอร์สโค้ดสำหรับแต่ละฐานข้อมูล

หนึ่งไลบรารีหลายเนมสเปซ:

การมีเนมสเปซหลายรายการในไลบรารีเดียวก็มีประโยชน์ในแง่ของความสามารถในการอ่าน ถ้าในคลาสฉันใช้เนมสเปซเพียงอันเดียวฉันใส่อันนี้ไว้ที่ส่วนบนของไฟล์

  • การมีเนมสเปซทั้งหมดของไลบรารีขนาดใหญ่จะค่อนข้างสับสนทั้งสำหรับผู้ที่อ่านซอร์สโค้ดและสำหรับผู้เขียนเองโดย Intellisense มีสิ่งต่าง ๆ มากมายเกินกว่าที่จะแนะนำในบริบทที่กำหนด

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


เคสที่สองไม่ต้องการชื่อไฟล์ที่จะแยกออกจากเนมสเปซ นอกจากนี้ยังเป็นไปได้ที่จะฝังหลายชุดลงใน DLL เดียวกัน (เช่นใช้ILMerge ) Java ใช้แนวทางนี้
ไบรอัน

2

ดูเหมือนว่าคุณกำลังเลือกที่จะใช้คำศัพท์มากเกินไปทั้ง "namespace" และ "module" ไม่น่าแปลกใจเลยที่คุณเห็นว่าสิ่งนั้นเป็น "ทางอ้อม" เมื่อสิ่งเหล่านั้นไม่ตรงกับคำจำกัดความของคุณ

ในภาษาส่วนใหญ่ที่รองรับเนมสเปซรวมถึง C #, เนมสเปซไม่ใช่โมดูล เนมสเปซเป็นวิธีการกำหนดขอบเขตชื่อ โมดูลเป็นวิธีการกำหนดขอบเขตพฤติกรรม

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

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

ใน Scheme หากคุณต้องการโหลดไลบรารี่ภายนอกคุณต้องทำอะไรอย่าง(#%require (lib "mylib.ss"))ก่อนหรือใช้อินเทอร์เฟซฟังก์ชั่นต่างประเทศโดยตรงตามที่ฉันจำได้ หากคุณใช้ไบนารีภายนอกคุณมีจำนวนงานเท่ากันเพื่อแก้ไขไบนารีภายนอก โอกาสที่คุณจะใช้ห้องสมุดเป็นส่วนใหญ่จึงมักใช้ว่ามี shim-based shim ที่เป็นนามธรรมซึ่งมาจากคุณ แต่ถ้าคุณต้องเขียนการรวมของคุณเองกับไลบรารี่ของบุคคลที่สามคุณจะต้องทำงานบางอย่างเพื่อ "โหลด " ห้องสมุด.

ใน Ruby, Modules, Namespaces และ File Names นั้นมีการเชื่อมต่อน้อยกว่าที่คุณคิด LOAD_PATH ทำให้สิ่งต่าง ๆ ซับซ้อนเล็กน้อยและการประกาศโมดูลสามารถทำได้ทุกที่ Python อาจใกล้เคียงกับการทำสิ่งต่าง ๆ ในแบบที่คุณคิดว่าคุณเห็นใน Scheme ยกเว้นว่าไลบรารี่ของบุคคลที่สามใน C ยังคงเพิ่มรอยย่น (เล็ก)

นอกจากนี้ภาษาที่พิมพ์แบบไดนามิกเช่น Ruby, Python และ Lisp มักไม่มีวิธีการ "สัญญา" ที่เหมือนกันกับภาษาที่พิมพ์แบบคงที่ ในภาษาที่พิมพ์แบบไดนามิกคุณมักจะสร้าง "ข้อตกลงของสุภาพบุรุษ" รหัสนั้นจะตอบสนองต่อวิธีการบางอย่างและถ้าชั้นเรียนของคุณดูเหมือนจะพูดภาษาเดียวกันทุกอย่างจะดี ภาษาที่พิมพ์แบบคงที่มีกลไกเพิ่มเติมเพื่อบังคับใช้กฎเหล่านี้ในเวลารวบรวม ใน C # การใช้สัญญาดังกล่าวช่วยให้คุณสามารถรับประกันการยึดมั่นกับอินเทอร์เฟซเหล่านี้อย่างน้อยมีประโยชน์ในระดับปานกลางซึ่งช่วยให้คุณสามารถรวมปลั๊กอินและการแทนที่ด้วยการรับประกันระดับสามัญของคอมมอนเพราะคุณรวบรวมกับสัญญาเดียวกัน ใน Ruby หรือ Scheme คุณตรวจสอบข้อตกลงเหล่านี้ด้วยการเขียนการทดสอบที่ใช้งานได้จริง

มีประโยชน์ประสิทธิภาพที่วัดได้จากการรับประกันเวลารวบรวมเหล่านี้เป็นวิธีการภาวนาไม่จำเป็นต้องส่งสองครั้ง เพื่อให้ได้รับประโยชน์เหล่านี้ในบางสิ่งบางอย่างเช่น Lisp, Ruby, JavaScript หรือที่อื่น ๆ สิ่งที่ตอนนี้ยังคงเป็นกลไกที่แปลกใหม่เล็กน้อยของการรวบรวมคลาสในแบบคงที่เพียงครั้งเดียวใน VMs เฉพาะ

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


1
เกี่ยวกับการจัดการการอ้างอิงที่คุณอาจต้องการที่จะดูที่NuGet นี่เป็นบทความที่ดีเกี่ยวกับเรื่องนี้จาก Phil Haack
Conrad Frix

ในการใช้งานโครงการ R6RS ฉันได้ใช้ (ตัวอย่างเช่น Ikarus, Chez และ Ypsilon) ได้รับการจัดการโดยอัตโนมัติตามการนำเข้าห้องสมุด พบการอ้างอิงและถ้าจำเป็นรวบรวมและแคชสำหรับการนำเข้าในอนาคต
dharmatech

คุ้นเคยกับ Nuget และทำให้ความคิดเห็นของฉันว่ามันเป็น "ค่อนข้างอ่อน"
JasonTrue
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.