MissingMethodException после извлечения базового интерфейса

Я разделил интерфейс внутри библиотеки пакетов Nuget на более простой базовый интерфейс (без одного свойства из оригинала) и сделал оригинал производным от нового базового интерфейса.

Создание экземпляров в приложениях-потребителях происходит через Managed Extensibility Framework (MEF), используя внедрение свойств с атрибутами [Import] и реализации с [Export(typeof(IFooConfigurations))].

Это не должно быть критическим изменением для приложений, использующих старый интерфейс и реализацию. Но в некоторых случаях загружаются разные библиотеки, которые используют старые версии интерфейса и реализации. Это приводит к возникновению MissingMethodExceptions во время выполнения, говорящего о том, что метод или свойство (метод get) не существует, например свойство списка Configurations в примере.

Старый:

public interface IFooConfigurations
{
    int ConfigurationsIdentifier { get; }

    IReadOnlyList<Configuration> Configurations { get; }
}

Новое:

public interface IBaseFooConfigurations
{
    // without the ConfigurationsIdentifier

    IReadOnlyList<Configuration> Configurations { get; }
}

public interface IFooConfigurations : IBaseFooConfigurations
{
    int ConfigurationsIdentifier { get; }

    // Configurations inherited from IBaseFooConfigurations
}

Реализация (без изменений)

[Export(typeof(IFooConfigurations)]
public class FooConfigurations : IFooConfigurations
{
    // implementations of ConfigurationsIdentifier and Configurations 
}

Использование (без изменений), разрешено через MEF

public class FooApplicationClass
{
    [Import]
    private IFooConfigurations ConfigurationsOwner { get; set; }
}

Отследить эту ошибку и найти возможные причины довольно сложно, так как в обычной среде разработки она не возникает.

Может ли это быть решением, реплицировать все старые свойства и методы, которые сейчас есть в базовом интерфейсе, в новой версии интерфейса IFooConfigurations с ключевым словом new, но при этом производными от нового IBaseFooConfigurations?

Возможное решение?

public interface IFooConfigurations : IBaseFooConfigurations
{
    int ConfigurationsIdentifier { get; }

    new IReadOnlyList<Configuration> Configurations { get; }
}

РЕДАКТИРОВАТЬ: кажется, что сохранение элементов исходного интерфейса, скрытие унаследованных с помощью ключевого слова «новое», решило проблему. Вероятно, старые приложения и библиотеки, работающие с исходным интерфейсом, не могли разрешать унаследованные члены как части исходного интерфейса. Тем не менее, явные реализации и макеты потенциально могут быть проблематичными. Предстоит еще провести тестирование.


person Erik Hart    schedule 08.03.2019    source источник
comment
может быть где-то есть ссылка....   -  person Abhinaw Kaushik    schedule 08.03.2019


Ответы (1)


Члены интерфейса, унаследованные от другого интерфейса, не эквивалентны членам, которые определены в самом интерфейсе. Таким образом, перемещение элементов в базовый интерфейс и наследование от него является критическим изменением. Чтобы быть совместимыми с предыдущими версиями, члены интерфейса также должны быть определены сами по себе как «новые» (в C#).

Я подтвердил это с помощью простой тестовой программы, ссылаясь на разные сборки DLL с исходным единым интерфейсом, разделением и еще одним с разделением и дублированием «новых» членов. Так что это не проблема MEF.

К сожалению, эта проблема возникает только во время выполнения, после того как выпуск пакета nuget уже собран.

person Erik Hart    schedule 11.03.2019