2009-09-10 11 views
5

Ho appena finito di guardare un episodio di Bob Martin in NDC dove ha detto che le direttive "using" in C# nella parte superiore di una pagina sono negative a causa dell'accoppiamento stretto che creano/implicano tra i componenti.Alternative alla parola chiave direttiva "using" in C#?

In che modo è possibile utilizzare file dll esterni senza aggiungere un riferimento al progetto e un'istruzione using?

Ricordo che il V6 permetteva di creare un oggetto tramite la stringa del ProgId - Non sono sicuro che questa sia la tecnica che sto cercando, ma è un esempio di una lingua che non ha bisogno di un progetto riferimento per usare una dll.

MODIFICA: Here is a link to the conference. Scusa se non ho la citazione esatta o il minuto nella presentazione, vado a memoria.

+1

L'ha detto davvero, o è quello che hai capito di quello che ha detto? –

+3

Un collegamento a questo sarebbe utile. Mi piacerebbe sentire cosa ha effettivamente detto. – tvanfosson

+6

Giusto per evitare confusione, Microsoft si riferisce ad esso come l'uso di "direttiva". L'istruzione using (parola chiave) farebbe normalmente riferimento a quella usata nei metodi per chiamare automaticamente Dispose sulle risorse. – Ash

risposta

6

Non è la stessa usando affermazione che è male - è se si ottiene troppi di loro.

Una dichiarazione come using System; è raramente un problema in sé, ma se si dispone di un sacco (direi più di 3-6, a seconda di quelli) nello stesso file di codice, potrebbe essere un'indicazione di accoppiamento stretto.

Si potrebbe anche applicare una regola empirica simile al numero di riferimenti in un progetto stesso.

La soluzione per l'accoppiamento stretto è la programmazione alle interfacce e Iniezione di dipendenza (DI).

Il modo ProgId di fare cose che si possono ricordare da VB era semplicemente COM in azione. In sostanza, hai usato quel ProgId per ottenere un riferimento a un'istanza che ha implementato l'interfaccia desiderata. Lo svantaggio era che funzionava solo quando l'oggetto COM era registrato universalmente. Ti ricordi diavolo?

È possibile applicare lo stesso principio utilizzando determinati tipi di DI, solo che ora l'interfaccia è di tipo .NET e non definita in IDL e per l'implementazione concreta è necessaria una sorta di DI contenitore.

+1

Scriverò questo "potrebbe ** essere un'indicazione di accoppiamento stretto" invece di "se potrebbe essere un ** indicazione di accoppiamento stretto **" –

+0

@Vinko Vrsalovic: No, non sono d'accordo: Se hai venti affermazioni usando, è sicuramente un * indicazione * di accoppiamento stretto. –

+0

Quindi dillo: "è un ** indicazione ** di accoppiamento stretto" –

6

using è solo una scorciatoia per gli spazi dei nomi, non sono riferimenti a file esterni. Pertanto, questo non ha proprio senso.

In ogni caso, ciò che si può fare è avere un'interfaccia DLL (una DLL con solo interfacce), in modo da caricare e utilizzare in modo dinamico diversi assiemi e creare tipi (tramite riflessione) che è possibile trasmettere alle interfacce ben note. Questo è il modo corretto di allentare i riferimenti esterni mantenendo i vantaggi del linguaggio fortemente tipizzato e del binding anticipato.

Dai un'occhiata alle classi Assembly e AppDomain per caricare gli assembly e Activator per creare istanze di tipi per nome.

+6

concordato. Questo tizio che dice "usare" le affermazioni sono cattive chiaramente non sa di cosa sta parlando. – Noldorin

+4

@Noldorin: Robert C. Martin non sa di cosa sta parlando ?! –

+1

Oppure è stato frainteso. Chi era o ha torto non importa molto, perché il "messaggio ricevuto" non ha senso. – Lucero

7

Credo che Bob Martin si riferisca in realtà ai legami precoci e tardivi.

In .NET l'associazione tardiva è possibile tramite la riflessione e più specificamente la classe Activator che consente la creazione di un tipo in un assieme esterno utilizzando un nome di file o assembly.

Normalmente, l'utilizzo di direttive (non l'istruzione di utilizzo) va di pari passo con il riferimento diretto a un assieme esterno. vale a dire. Aggiungere un riferimento a un assieme e quindi aggiungere utilizzando le direttive per evitare di dover digitare la gerarchia dello spazio dei nomi completo quando si utilizzano i tipi esterni.

Quindi, se si trova il codice con un numero elevato di direttive di utilizzo nella parte superiore, è possibile che si faccia riferimento a molti altri tipi direttamente e quindi aumentando l'accoppiamento/dipendenza del codice su questi tipi.

Direi che è per questo che Bob si sta riferendo a loro come male. La risposta alla domanda "è davvero male?" è molto soggettivo e dipendente dal contesto.

In generale, tuttavia, il disaccoppiamento dei componenti è quasi sempre un buon obiettivo da raggiungere nella progettazione del software. Questo perché consente di modificare parti del sistema con un impatto minimo sul resto del sistema. Avendo letto uno o due dei libri di Bob Martins, mi aspetterei che questo è ciò che sta ottenendo.

1

Si può fare ciò a cui ci si riferisce attraverso la riflessione. È possibile caricare l'assembly in fase di esecuzione e riflettere attraverso di esso per ottenere le classi ecc. E chiamarle dinamicamente.

Personalmente, non lo farei per evitare l'accoppiamento. Per me è un cattivo uso della riflessione, e preferirei piuttosto aggiungerlo al progetto e riferirlo, a meno che non vi sia un motivo specifico per non farlo. Reflection aggiunge un sovraccarico al sistema e non ottieni il vantaggio della sicurezza in fase di compilazione.

+0

Inoltre, questa "tecnica" * non dovrebbe * evitare l'accoppiamento. Il tuo codice non è meno abbinato a una DLL esterna perché la stai chiamando dinamicamente - se la DLL non è presente, il tuo codice non funzionerà. – MusiGenesis

+1

Riduce l'accoppiamento se si dispone di un assembly di interfaccia e si caricano oggetti dinamici con interfacce. Anche l'iniezione di dipendenza è un buon approccio. – kenny

+0

@Kenny: hai perfettamente ragione in questo caso. Stavo più dicendo che se rimuovi un riferimento e lo carichi in modo dinamico, non stai migliorando la situazione. – MusiGenesis

2

Si potrebbe utilizzare riflessione:

// Load the assembly 
Assembly assembly = Assembly.LoadFrom(@"c:\path\Tools.dll"); 
// Select a type 
Type type = assembly.GetType("Tools.Utility"); 
// invoke a method on this type 
type.InvokeMember("SomeMethod", BindingFlags.Static, null, null, new object[0]); 
+4

Questo tipo di chiamata è chiamata late-binding e non solo è lenta e abbastanza soggetta a errori, ma è anche piuttosto ingombrante in linguaggi come C# che non sono progettati per supportare l'associazione tardiva fuori dalla scatola (ad esempio tramite magia del compilatore). Se possibile, eviterei questo approccio. – Lucero

+0

Meglio usare un framework DI per questo tipo di cose, onestamente. Meglio anche per il nonno. – Will