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.

НО: это решение кажется неправильным. Я все еще ищу официальное решение этой проблемы.

0 ответов

Другие вопросы по тегам