Aquí está mi solución. Al principio intenté crear un método de extensión. Probé varias cosas, leí el documento y exploré las propiedades, eventos y métodos disponibles en el contenedor y el catálogo, pero no pude hacer que funcionara nada.
Después de pensar en el problema, la única forma en que puedo encontrar una solución es crear un contenedor derivado que esté basado en CompositionContainer e implemente el método GetButDoNotCreate.
Actualización: Me di cuenta después de publicar que la solución solo funciona en el ejemplo simple que ha publicado donde solo GetExportedValue se utiliza para recuperar piezas de partes simples. A menos que use el contenedor como un simple localizador de servicio para las partes sin [Import] s que no funcionarán cuando se creen partes con [Import] s.
Aquí es la implementación:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
namespace GetButNotCreate
{
public class CustomContainer : CompositionContainer
{
private List<Type> composedTypes = new List<Type>();
public CustomContainer(ComposablePartCatalog catalog)
: base(catalog)
{
}
public new T GetExportedValue<T>()
{
if (!composedTypes.Contains(typeof(T)))
composedTypes.Add(typeof(T));
return base.GetExportedValue<T>();
}
public T GetButDoNotCreate<T>()
{
if (composedTypes.Contains(typeof(T)))
{
return base.GetExportedValue<T>();
}
throw new Exception("Type has not been composed yet.");
}
}
}
Funciona reemplazando el método GetExportedValue hacer un seguimiento de los tipos que se han compuesto hasta el momento y después de usar este para comprobar si hay Composición Tipo de GetButNotCreate. Lancé una excepción como la que mencionaste en tu pregunta.
Por supuesto, es posible que deba anular las sobrecargas de GetExportedValue (a menos que no las use, pero aun así, las anularía por seguridad) y tal vez agregue otros constructores y cosas si usa la clase. En este ejemplo, hice lo mínimo para que funcione.
Estas son las pruebas unitarias que ponen a prueba el nuevo método:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace GetButNotCreate
{
public interface IInterface { }
[Export(typeof(IInterface))]
public class MyClass : IInterface
{
}
[TestClass]
public class UnitTest1
{
[TestMethod]
[ExpectedException(typeof(Exception), "Type has not been composed yet.")]
public void GetButNotCreate_will_throw_exception_if_type_not_composed_yet()
{
var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly);
CustomContainer container = new CustomContainer(catalog);
container.ComposeParts(this);
var test = container.GetButDoNotCreate<IInterface>();
}
[TestMethod]
public void GetButNotCreate_will_return_type_if_it_as_been_composed()
{
var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly);
CustomContainer container = new CustomContainer(catalog);
container.ComposeParts(this);
var x = container.GetExportedValue<IInterface>();
var y = container.GetButDoNotCreate<IInterface>();
Assert.IsNotNull(y);
Assert.AreEqual(x, y);
}
}
}
Muestra que la GetButNotCreate lanzará una excepción si el tipo nunca ha sido exportado y que le proporcione este tipo si ya ha sido importado.
No pude encontrar ningún gancho en ningún lugar para comprobar (sin recurrir a la reflexión) para ver si MEF ha compuesto una pieza, por lo que esta solución CustomContainer sería mi mejor opción.
Me pregunto por qué aparentemente está probando el contenedor en las pruebas de su unidad? –
@MatthewAbbott - Estoy intentando escribir pruebas de sistemas en la capa ViewModel (construida con un primer diseño de ViewModel). Estas no son pruebas unitarias ... En lugar de manipular elementos de la interfaz de usuario, quiero meter la mano en el contenedor, agarrar el modelo de vista y lograr el mismo efecto. – Gishu
Más contexto aquí - http://caliburnmicro.codeplex.com/discussions/348548 – Gishu