提取基本接口后出现 MissingMethodException
MissingMethodException after extracting base interface
我在 Nuget 包库中将一个接口拆分为一个更简单的基本接口(没有 属性 原始接口),并使原始接口派生自新的基本接口。
消费应用程序中的实例化通过托管可扩展性框架 (MEF) 进行,使用具有 [Import]
属性的 属性 注入,以及具有 [Export(typeof(IFooConfigurations))]
的实现
对于使用旧接口和实现的应用程序,这不应该是一个重大更改。但在某些情况下,会加载不同的库,这些库使用旧的接口版本和实现。这会导致运行时出现 MissingMethodExceptions,表示方法或 属性(获取方法)不存在 - 例如示例中的 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; }
}
编辑: 似乎保留原始接口的成员,用 "new" 关键字隐藏继承的成员,解决了问题。可能,使用原始接口的较旧的应用程序和库无法将继承的成员解析为原始接口的一部分。但是,显式实现和模拟可能会带来麻烦。还有待测试。
从另一个接口继承的接口成员不等同于在接口本身中定义的成员。因此,将成员移动到基接口并从中继承是一个重大变化。为了向下兼容,接口的成员也必须自己定义,如"new"(在C#中)。
我用一个简单的测试程序证实了这一点,引用了具有原始单一接口、拆分和另一个具有拆分和重复 "new" 成员的 DLL 的不同版本。所以这不是MEF的问题。
不幸的是,这个问题只发生在运行时,在已经构建了 nuget 包的版本之后。
我在 Nuget 包库中将一个接口拆分为一个更简单的基本接口(没有 属性 原始接口),并使原始接口派生自新的基本接口。
消费应用程序中的实例化通过托管可扩展性框架 (MEF) 进行,使用具有 [Import]
属性的 属性 注入,以及具有 [Export(typeof(IFooConfigurations))]
对于使用旧接口和实现的应用程序,这不应该是一个重大更改。但在某些情况下,会加载不同的库,这些库使用旧的接口版本和实现。这会导致运行时出现 MissingMethodExceptions,表示方法或 属性(获取方法)不存在 - 例如示例中的 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; }
}
编辑: 似乎保留原始接口的成员,用 "new" 关键字隐藏继承的成员,解决了问题。可能,使用原始接口的较旧的应用程序和库无法将继承的成员解析为原始接口的一部分。但是,显式实现和模拟可能会带来麻烦。还有待测试。
从另一个接口继承的接口成员不等同于在接口本身中定义的成员。因此,将成员移动到基接口并从中继承是一个重大变化。为了向下兼容,接口的成员也必须自己定义,如"new"(在C#中)。
我用一个简单的测试程序证实了这一点,引用了具有原始单一接口、拆分和另一个具有拆分和重复 "new" 成员的 DLL 的不同版本。所以这不是MEF的问题。
不幸的是,这个问题只发生在运行时,在已经构建了 nuget 包的版本之后。