MEF против IAsyncDisposable или итерация по всем экземплярам экспорта
Я поделился экспортом MEF, который реализует. Если экспорт в MEF реализуетон будет удален, когда контейнер композиции (или, возможно, каталог) будет удален.
не распознается MEF. Есть ли решение этой проблемы?
Если нет: если приложение будет закрыто, я пытаюсь перебрать все уже созданные экспорты, которые реализуются, но, похоже, это невозможно сделать.
Предположим, что у меня есть типизированный метод (возможно, созданный с помощью отражения), который я могу вызватьCompositionContainer.GetExport<T>()
который возвращает . Проблема в том, что
IsValueCreated
является
false
- даже если у этого импорта есть работающий общий экземпляр.
Есть ли способ перебрать все экспорты, которые уже были созданы?
Этот код показывает, что
Lazy<T>
-instance не содержит уже известного экспортируемого значения:
public class Program
{
public static void Main()
{
using var catalog = new AssemblyCatalog(typeof(Program).Assembly);
using var container = new CompositionContainer(catalog);
var dummyInstance = container.GetExport<Foo>().Value;
Console.WriteLine($"HasInstance: {dummyInstance is not null}");
var export = container.GetExport<Foo>();
Console.WriteLine($"IsValueCreated: {export.IsValueCreated}");
}
}
[Export]
[PartCreationPolicy(CreationPolicy.Shared)]
public class Foo
{
}
Результат:
HasInstance: True
IsValueCreated: False
РЕДАКТИРОВАТЬ
Я нашел «решение» этой проблемы, используя множество имен отражений и магических полей:
var catalogExportProviderProperty = compositionContainer
.GetType()
.GetProperty("CatalogExportProvider", BindingFlags.Instance | BindingFlags.NonPublic) ??
throw ReflectionErrors.MissingProperty(
compositionContainer.GetType(),
"CatalogExportProvider");
var catalogExportProvider =
catalogExportProviderProperty.GetValue(compositionContainer) ??
throw new InvalidOperationException(
$@"Uninitialized property 'CatalogExportProvider' in {compositionContainer.GetType().Name}.");
var partsToDisposeField =
catalogExportProvider.GetType().GetField("_partsToDispose", BindingFlags.Instance | BindingFlags.NonPublic) ??
throw ReflectionErrors.MissingField(catalogExportProvider.GetType(), "_partsToDispose");
var partsToDispose = partsToDisposeField.GetValue(catalogExportProvider) as IEnumerable ??
throw new InvalidOperationException($@"Unable to retrieve disposable parts from {catalogExportProvider.GetType()}.");
foreach (var item in partsToDispose.OfType<object>())
{
var cachedInstanceProperty = item.GetType().GetProperty("CachedInstance", BindingFlags.Instance | BindingFlags.NonPublic) ??
throw ReflectionErrors.MissingProperty(item.GetType(), "CachedInstance");
var cachedInstance = cachedInstanceProperty.GetValue(item, index: null);
if (cachedInstance is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
}
Это работает, потому что существует спецификация реализации , согласно которой каждый реализующий тип
IAsyncDisposable
следует также реализовать
IDisposable
.
НО: это решение кажется неправильным. Я все еще ищу официальное решение этой проблемы.