Вот мое решение.Сначала я попытался создать метод расширения.Я попробовал несколько вещей, прочитал документацию и изучил доступные свойства, события и методы контейнера и каталога, но ничего не смог сделать.
Подумав о проблеме, единственный способ найти решение - создать производный контейнер, основанный на CompositionContainer и реализующий метод GetButDoNotCreate.
Обновление:После публикации я понял, что решение работает только в простом примере, который вы опубликовали, где только GetExportedValue используется для извлечения деталей из простых деталей.Если вы не используете контейнер как простой сервисный локатор для деталей без [Import], которые не будут работать при создании деталей с [Import].
Вот реализация:
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.");
}
}
}
Он работает, переопределяя метод GetExportedValue для отслеживания типов, которые были составлены до сих пор, а затем использует это для проверки композиции типов в GetButNotCreate.Я бросил исключение, как вы упомянули в своем вопросе.
Конечно, вам может понадобиться переопределить перегрузки GetExportedValue (если вы не используете их, но даже в этом случае я бы переопределил их в любом случае для безопасности) и, возможно, добавьте другие конструкторы и прочее, если вы используетеучебный класс.В этом примере я сделал минимум, чтобы заставить его работать.
Вот модульные тесты, которые тестируют новый метод:
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);
}
}
}
Это показывает, что GetButNotCreate выдает исключение, еслитип никогда не экспортировался, и он вернет этот тип, если он уже был импортирован.
Я нигде не мог найти хуков, чтобы проверить (не прибегая к рефлексии), чтобы увидеть, состоит ли MEF из какой-либо части, так что это решение CustomContainer было бы моим лучшим выбором.