Perché i moduli .NET separano i nomi dei file dei moduli dagli spazi dei nomi?


9

Nelle implementazioni del linguaggio di programmazione Scheme (standard R6RS) posso importare un modulo come segue:

(import (abc def xyz))

Il sistema proverà a cercare un file in $DIR/abc/def/xyz.slscui si $DIRtrova una directory in cui conservare i moduli Scheme. xyz.slsè il codice sorgente per il modulo ed è compilato al volo, se necessario.

I sistemi di moduli Ruby, Python e Perl sono simili in questo senso.

C # d'altra parte è un po 'più coinvolto.

Innanzitutto, hai i file dll a cui devi fare riferimento per progetto. È necessario fare riferimento a ciascuno in modo esplicito. Questo è più complicato che dire, trascinando i file dll in una directory e facendo in modo che C # li raccolga per nome.

In secondo luogo, non esiste una corrispondenza di denominazione individuale tra il nome file dll e gli spazi dei nomi offerti dalla dll. Posso apprezzare questa flessibilità, ma può anche sfuggire di mano (e ha).

Per renderlo concreto, sarebbe bello se, quando dico questo using abc.def.xyz;, C # tentasse di trovare un file abc/def/xyz.dll, in una directory in cui C # sa cercare (configurabile per progetto).

Trovo il modo di gestire i moduli Ruby, Python, Perl, Scheme più elegante. Sembra che le lingue emergenti tendano ad andare con il design più semplice.

Perché il mondo .NET / C # fa le cose in questo modo, con un ulteriore livello di riferimento indiretto?


10
Il meccanismo di assemblaggio e risoluzione delle classi di .NET ha funzionato perfettamente per oltre 10 anni. Penso che ti manchi un equivoco fondamentale (o una ricerca insufficiente) sul perché sia ​​progettato in questo modo - ad esempio per supportare il reindirizzamento degli assemblaggi ecc. Al momento del bind e molti altri utili meccanismi di risoluzione
Kev,

Sono abbastanza sicuro che la risoluzione DLL da un'istruzione using interromperebbe l'esecuzione affiancata. Inoltre, se ci fosse un 1 a 1, avresti bisogno di 50 dll per tutti gli spazi dei nomi in mscorlib, o dovrebbero abbandonare l'idea degli spazi dei nomi
Conrad Frix,

Un ulteriore livello di riferimento indiretto? Hmmmmm .... dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/Spi07g.html
user541686

@gilles Grazie per la modifica e il miglioramento della domanda!
dharmatech,

Alcuni dei tuoi punti sono peculiari di Visual Studio e confrontarli con un linguaggio non è abbastanza corretto ( ad es . Riferimenti DLL nei progetti). Un confronto migliore per l'intero ambiente .NET sarebbe Java + Eclipse.
Ross Patterson,

Risposte:


22

La seguente annotazione nelle Linee guida per la progettazione del quadro, sezione 3.3. Nomi di assiemi e DLL offre informazioni dettagliate sul perché gli spazi dei nomi e gli assiemi sono separati.

BRAD ABRAMS All'inizio della progettazione del CLR abbiamo deciso di separare la vista dello sviluppatore della piattaforma (spazi dei nomi) dalla vista dell'imballaggio e della distribuzione della piattaforma (assiemi). Questa separazione consente a ciascuno di essere ottimizzato in modo indipendente in base ai propri criteri. Ad esempio, siamo liberi di fattorizzare gli spazi dei nomi per i tipi di gruppo che sono funzionalmente correlati (ad es. Tutte le cose I / O in System.IO) mentre gli assiemi possono essere fattorizzati per motivi di prestazioni (tempo di caricamento), distribuzione, manutenzione o versioning .


Sembra la fonte più autorevole finora. Grazie Corrado!
Dharmatech,

+1 per ottenere la risposta dannatamente autorevole. Inoltre, ogni domanda " perché C # fa <X> " deve anche essere vista attraverso l'obiettivo di " Java fa <X> come segue: ... ", perché C # è stata (esplicitamente o meno) una reazione a Sun e Differenti ordini del giorno di Microsoft per Java su Windows.
Ross Patterson,

6

Aggiunge flessibilità e consente di caricare le librerie (ciò che chiamate moduli nella vostra domanda) su richiesta.

Uno spazio dei nomi, più librerie:

Uno dei vantaggi è che posso facilmente sostituire una libreria con un'altra. Diciamo che ho uno spazio dei nomi MyCompany.MyApplication.DALe una libreria DAL.MicrosoftSQL.dll, che contiene tutte le query SQL e altre cose che potrebbero essere specifiche del database. Se voglio che l'applicazione sia compatibile con Oracle, aggiungo semplicemente DAL.Oracle.dll, mantenendo lo stesso spazio dei nomi. Da adesso, posso distribuire l'applicazione con una libreria per i clienti che necessitano della compatibilità con Microsoft SQL Server e con l'altra libreria per i clienti che utilizzano Oracle.

Cambiare lo spazio dei nomi a questo livello porterebbe a un codice duplicato o alla necessità di andare a cambiare tutti usingi messaggi di testo all'interno del codice sorgente per ciascun database.

Una libreria, più spazi dei nomi:

Avere più spazi dei nomi in una libreria è anche vantaggioso in termini di leggibilità. Se, in una classe, utilizzo solo uno degli spazi dei nomi, inserisco solo questo in cima al file.

  • Avere tutti gli spazi dei nomi di una grande biblioteca sarebbe piuttosto confuso sia per la persona che legge il codice sorgente sia per lo scrittore stesso, con Intellisense che ha troppe cose da suggerire in un determinato contesto.

  • Avere librerie più piccole, una libreria per file avrebbe un impatto sulle prestazioni: ogni libreria deve essere caricata su richiesta in memoria ed elaborata dalla macchina virtuale durante l'esecuzione dell'applicazione; meno file da caricare significa prestazioni leggermente migliori.


Il secondo caso non richiede che i nomi dei file siano separati dagli spazi dei nomi (sebbene consentire tale separazione renda significativamente più semplice la separazione), poiché un determinato assembly può avere facilmente molte sottocartelle e file. Inoltre, è anche possibile incorporare più assembly nella stessa DLL (ad esempio, utilizzando ILMerge ). Java funziona adotta questo approccio.
Brian,

2

Sembra che tu stia scegliendo di sovraccaricare la terminologia di "spazio dei nomi" e "modulo". Non dovrebbe sorprendere vedere le cose come "indirette" quando non si adattano alle tue definizioni.

Nella maggior parte delle lingue che supportano gli spazi dei nomi, incluso C #, uno spazio dei nomi non è un modulo. Uno spazio dei nomi è un modo di individuare i nomi. I moduli sono un modo di comportamento di scoping.

In generale, mentre il runtime .Net supporta l'idea di un modulo (con una definizione leggermente diversa da quella che si sta usando implicitamente), è piuttosto raramente usato; L'ho visto usato solo in progetti creati in SharpDevelop, principalmente per poter costruire una singola DLL da moduli costruiti in lingue diverse. Invece, costruiamo librerie usando una libreria collegata dinamicamente.

In C #, gli spazi dei nomi si risolvono senza alcun "livello di riferimento indiretto" purché siano tutti nello stesso binario; qualsiasi indiretta richiesta è una responsabilità del compilatore e del linker a cui non devi pensare molto. Una volta che inizi a creare un progetto con più dipendenze, fai riferimento a librerie esterne. Una volta che il progetto ha fatto riferimento a una libreria esterna (DLL), il compilatore lo trova per te.

In Scheme, se devi caricare una libreria esterna, devi fare qualcosa come (#%require (lib "mylib.ss"))prima, oppure utilizzare direttamente l'interfaccia di funzione esterna, come ricordo. Se stai usando binari esterni, hai la stessa quantità di lavoro per risolvere i binari esterni. È probabile che tu abbia usato principalmente librerie così comunemente usate che esiste uno shim basato su Schema che lo sottrae da te, ma se mai dovessi scrivere la tua integrazione con una libreria di terze parti, dovrai essenzialmente fare del lavoro per "caricare " la Biblioteca.

In Ruby, Modules, Namespace e File Names sono in realtà molto meno connessi di quanto sembri; LOAD_PATH rende le cose un po 'complicate e le dichiarazioni del modulo possono essere ovunque. Python è probabilmente più vicino a fare le cose come pensi di vedere in Scheme, tranne per il fatto che le librerie di terze parti in C aggiungono ancora una (piccola) ruga.

Inoltre, i linguaggi tipizzati dinamicamente come Ruby, Python e Lisp in genere non hanno lo stesso approccio ai "contratti" dei linguaggi tipizzati staticamente. Nelle lingue tipizzate dinamicamente, di solito stabilisci solo una sorta di "accordo di gentiluomo" che il codice risponderà a determinati metodi, e se le tue classi sembrano parlare la stessa lingua, tutto va bene. I linguaggi tipizzati staticamente hanno meccanismi aggiuntivi per applicare queste regole in fase di compilazione. In C #, l'utilizzo di un contratto del genere consente di fornire garanzie di aderenza almeno moderatamente utili a queste interfacce, che consente di raggruppare plug-in e sostituzioni con un certo grado di garanzia di comunanza perché tutti compilano lo stesso contratto. In Ruby o Scheme, si verificano questi accordi scrivendo test che funzionano in fase di esecuzione.

Le prestazioni in termini di tempo di compilazione offrono un vantaggio misurabile in termini di prestazioni, in quanto una chiamata al metodo non richiede una doppia spedizione. Al fine di ottenere questi benefici in qualcosa come Lisp, Ruby, JavaScript o altrove, sono necessari meccanismi che ora sono ancora leggermente esotici di classi di compilazione statica just-in-time in VM specializzate.

Una cosa per cui l'ecosistema C # ha ancora un supporto relativamente immaturo è la gestione di queste dipendenze binarie; Java ha avuto Maven per diversi anni per assicurarsi di avere tutte le dipendenze necessarie, mentre C # ha ancora un approccio abbastanza primitivo simile a MAKE che prevede di posizionare strategicamente i file nel posto giusto prima del tempo.


1
Per quanto riguarda la gestione delle dipendenze potresti dare un'occhiata a NuGet . Ecco un bell'articolo a riguardo di Phil Haack
Conrad Frix,

Nelle implementazioni dello Schema R6RS che ho usato (Ikarus, Chez e Ypsilon, per esempio) le dipendenze vengono gestite automaticamente, in base alle importazioni della libreria. Le dipendenze vengono rilevate e, se necessario, compilate e memorizzate nella cache per le importazioni future.
dharmatech,

Familiarità con Nuget, e quindi il mio commento che è "relativamente immaturo"
JasonTrue
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.