2012-06-25 14 views
6

Estoy usando MEF para permitir a los usuarios ampliar mi biblioteca de C#. Hasta ahora funciona bien, pero ahora estoy tratando de usarlo de una manera que nunca antes había visto.¿Cómo usar MEF para permitir que los complementos anulen la funcionalidad existente?

El caso de uso principal para MEF que he visto hasta ahora es la siguiente:

  • Aplicación expone interfaz de primitivas (IPerson)
  • biblioteca externa utiliza MEF y las interfaces de primitivas para ampliar la funcionalidad de la biblioteca principal (por ejemplo, IPoliceman : IPerson, añade una funcionalidad)
  • aplicación utiliza ImportMany para buscar IPerson correcta dependiendo de lo que debe hacer

Pero necesito algo como esto: supongamos que tengo una calculadora de impuestos que toma una serie de parámetros y devuelve un impuesto estimado según esos parámetros. Quiero que los usuarios puedan crear complementos con MEF que modifique cómo se hacen esos cálculos. Solo un complemento que hace esto debería poder cargarse en cualquier momento. De lo contrario, ¿cómo decido qué implementación alternativa usar?

Básicamente, mi pregunta se reduce a esto: generalmente MEF permite y agrega implementaciones de clases y métodos. ¿Cómo lo uso para permitir a los usuarios reemplazar una implementación?

+1

Esto parece super simple. Simplemente permita que se cargue un complemento, y si no hay ninguno disponible, use la implementación predeterminada. Luego puede hacer que el usuario elija en su configuración. – eandersson

Respuesta

3

De lo que estás hablando es en realidad una forma diferente de ver el mismo problema. La respuesta es más simple de lo que parece: para cualquier comportamiento que desee que un cliente pueda anular, simplemente ponga ese comportamiento en un complemento.

No hay nada que diga que no puede escribir complementos solo porque usted es el autor de la aplicación. Coloque su clase TaxCalculator en un complemento y exponga una interfaz que permita a los usuarios escribir sus propias calculadoras de impuestos. En tiempo de ejecución, si tiene más de uno cargado, elija uno que no sea el suyo. Desde el primer momento, usará su plugin calculador de impuestos, por lo que funcionará exactamente de la manera que espera. Si el usuario crea su propio complemento de calculadora de impuestos y lo coloca en el directorio correcto, en su lugar lo usa, permitiéndole de hecho "anular" su funcionalidad original.

+0

tiene sentido, gracias! ¿Qué sucede si se cargan dos complementos que intentan anular la misma implementación? ¿Debo dejar que cada complemento sobrescriba los cambios de los demás o debería lanzar una excepción? Y si lanzo una excepción, ¿cómo puedo detectar el conflicto en primer lugar? –

+0

La forma en que desee manejarlo depende de su caso comercial. A veces una excepción es una buena idea, a veces solo quieres elegir una. Puede detectar el conflicto cuando carga los ensamblajes. Si hay varios ensambles que exportan su interfaz ITaxCollector (incluso después de eliminar el suyo de la lista), sabe que hay un conflicto. –

+0

Ok, gracias. Tendré que pensar un poco sobre la excepción vs. escoger una. ¡Gracias por la ayuda! –

1

No estoy seguro de cuánto sentido va a tener, pero déjame intentarlo.

Haría una clase TaxCalculatorManager. Esa clase podría cargar todas las implementaciones ITaxCalculator de MEF. A partir de ahí, podría tener algo en el atributo Export que permita la clasificación de las implementaciones. Luego, cuando necesite calcular los impuestos, deberá llamar al TaxCalculatorManager.Calculate, que clasificaría las implementaciones ITaxCalculator y llamará al Calculate al ganador.

Avísame si necesitas que aclare algún punto.

+0

Según lo observado por Fuji, si hay varias implementaciones, puede permitir que el usuario seleccione el ganador. – cadrell0

+0

Gracias por su respuesta. Me gusta la idea de clasificar las implementaciones según la importancia ... Lo investigaré. –

11

Normalmente, cuando intenta anular una exportación que ya está presente en la aplicación, obtendrá una excepción de cardinalidad para [Import(typeof(IFoo)] porque MEF espera que esté disponible exactamente una exportación coincidente.

Sin embargo, puede poner sus complementos en un proveedor de exportación por separado y darle prioridad.Aquí yo que para una subcarpeta "plugins" dentro de la carpeta de la aplicación:

Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
string exeLocation = Path.GetDirectoryName(executingAssembly.Location); 
string pluginPath = Path.Combine(exeLocation, "plugins"); 

var pluginCatalog = new DirectoryCatalog(pluginPath); 
var pluginExportProvider = new CatalogExportProvider(pluginCatalog); 

var appCatalog = new DirectoryCatalog(exeLocation,"*"); 
var appExportProvider = new CatalogExportProvider(appCatalog); 

var container = new CompositionContainer(
    pluginExportProvider, appExportProvider); 

pluginExportProvider.SourceProvider = container; 
appExportProvider.SourceProvider = container; 

El orden de los proveedores de exportación a medida que pasaba al recipiente de composición determina la prioridad: si una exportación es proporcionada tanto por los plugins y la aplicación partes, entonces los complementos tendrán prioridad.

Cuestiones relacionadas