2009-09-10 24 views
5

Acabo de ver un episodio de Bob Martin en NDC, donde dijo que las directivas de "uso" en C# en la parte superior de una página son malas debido al estrecho acoplamiento que crean/implican entre los componentes.Alternativas a la palabra clave directiva "using" en C#?

¿De qué manera se pueden usar los archivos .dlls externos sin agregar una referencia de proyecto y una instrucción using?

Recuerdo que V6 solía permitir crear un objeto por la cadena del ProgId - No estoy seguro de que sea la técnica que estoy buscando, pero es un ejemplo de un lenguaje que no necesitaba un proyecto referencia para usar un dll.

EDITAR: Here is a link to the conference. Lo siento, no tengo la cita exacta o el minuto en la presentación, voy de memoria.

+1

¿Realmente dijo eso, o eso es lo que entendiste de lo que dijo? –

+3

Un enlace a esto sería útil. Me gustaría escuchar lo que realmente dijo. – tvanfosson

+6

Para evitar confusiones, Microsoft se refiere a ella como la "directiva" que utiliza. La declaración de uso (palabra clave) normalmente se referiría a la que se usa dentro de los métodos para llamar automáticamente Disposición a los recursos. – Ash

Respuesta

6

no es la misma mediante declaración que es malo - es si obtiene demasiados de ellos.

una declaración como using System; no suele ser un problema en sí mismo, pero si usted tiene un montón (yo diría que más de 3-6, dependiendo de cuáles) en el mismo archivo de código, podría ser una indicación de acoplamiento apretado.

También podría aplicar una regla de oro similar a la cantidad de referencias en un proyecto en sí.

La solución para el acoplamiento ajustado es la programación para las interfaces y Dependency Injection (DI).

La manera ProgId de hacer las cosas que puedes recordar de VB fue simplemente COM en acción. En esencia, usaste ese ProgId para obtener una referencia a una instancia que implementó la interfaz deseada. Lo malo fue que esto solo funcionó cuando el objeto COM se registró universalmente. ¿Recuerdas todo el infierno?

Todavía puede aplicar el mismo principio con ciertos sabores de DI, solo que ahora la interfaz es del tipo .NET y no está definida en IDL, y necesita algún tipo de Contenedor DI para suministrar la implementación concreta.

+1

Escribiría que "** podría ** ser una indicación de acoplamiento ajustado" en lugar de "si podría ser una ** indicación de acoplamiento ajustado **" –

+0

@Vinko Vrsalovic: No, no estoy de acuerdo: Si tiene veinte instrucciones de uso, es definitivamente una * indicación * de acoplamiento ajustado. –

+0

Entonces dígalo: "es una ** indicación ** de acoplamiento ajustado" –

6

using es solo un acceso directo a espacios de nombres, no son referencias a archivos externos. Por lo tanto, esto simplemente no tiene sentido.

De todos modos, lo que se puede hacer es tener una interfaz DLL (una DLL con solo interfaces), para cargar dinámicamente y utilizar diferentes ensambles y crear tipos (a través de la reflexión) que puede convertir a las interfaces conocidas. Esta es la forma adecuada de aflojar referencias externas mientras se mantienen los beneficios del lenguaje fuertemente tipado y la vinculación temprana.

Eche un vistazo a las clases Assembly y AppDomain para cargar ensamblajes, y Activator para crear instancias de tipo por nombre.

+6

De acuerdo. Este chico que dice 'usar' las declaraciones son malas, claramente no sabe de lo que está hablando. – Noldorin

+4

@Noldorin: Robert C. Martin no sabe de qué está hablando? –

+1

O fue malentendido. Quien estaba o está equivocado no importa mucho, porque el "mensaje recibido" no tiene sentido. – Lucero

7

Creo que Bob Martin se está refiriendo a la vinculación temprana versus tardía.

En .NET enlace posterior es posible a través de la reflexión y más específicamente la clase Activador que permite la creación de un tipo en un conjunto externo con un nombre de archivo o nombre de conjunto.

Normalmente, el uso de directivas (no el enunciado de uso) va de la mano con la referencia directa de un ensamblaje externo. es decir. Agregue una referencia a un ensamblaje y luego agregue el uso de directivas para evitar la necesidad de escribir la jerarquía completa del espacio de nombres cuando use los tipos externos.

Así que si encuentra que su código tiene una gran cantidad de directivas de uso en la parte superior, es posible que esté haciendo referencia a muchos otros tipos directamente y aumentando el acoplamiento/dependencia de su código en estos tipos.

Supongo que es por eso que Bob se refiere a ellos como malo. La respuesta a la pregunta "¿es esto realmente malo?" es muy subjetivo y depende del contexto.

En general, el desacoplamiento de componentes es casi siempre un buen objetivo para diseñar software. Esto se debe a que le permite cambiar partes de su sistema con un impacto mínimo en el resto del sistema. Después de haber leído uno o dos de los libros de Bob Martins, esperaría que esto es lo que está tratando de decir.

1

Puede hacer lo que se refiere a través de la reflexión. Puede cargar el ensamblaje en tiempo de ejecución y reflejarlo para obtener las clases, etc. y llamarlas dinámicamente.

Personalmente, yo no haría esto para evitar el acoplamiento. Para mí eso es un mal uso de la reflexión, y preferiría agregarlo al proyecto y hacer referencia a él, a menos que haya una razón específica para no hacerlo. La reflexión agrega sobrecarga al sistema y no obtiene la ventaja de la seguridad del tiempo de compilación.

+0

Además, esta "técnica" * no * evitaría el acoplamiento. Su código no está menos acoplado a una DLL externa porque la está llamando dinámicamente; si la DLL no está allí, su código no funcionará. – MusiGenesis

+1

Reduce el acoplamiento si tiene un conjunto de interfaz y carga dinámicamente objetos que tienen interfaces. La inyección de dependencia también es un buen enfoque. – kenny

+0

@Kenny: tienes toda la razón en ese caso. Estaba más convencido de que si elimina una referencia y la carga dinámicamente, no está mejorando la situación. – MusiGenesis

2

Se podría utilizar la reflexión:

// 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

Este tipo de invocación se denomina enlace tardío y no solo es lento y bastante propenso a errores, sino también bastante engorroso en idiomas como C# que no están diseñados para admitir el enlace tardío (p. Ej., A través del compilador mágico). Si es posible, evitaría este enfoque. – Lucero

+0

Es mejor usar un marco DI para este tipo de cosas, sinceramente. Mejor para los noobish también. – Will

Cuestiones relacionadas