是否可以通过从为该方法提供默认实现的接口派生来重写方法实现?如果不是,我应该如何重构我的代码以避免对接口实现的显式方法调用?
以下是我的项目中类结构的概述:
interface IInputProcessor
{
public ProcessInputsResult ProcessInputs(Item[] inputs);
}
abstract class MachineComponent : IInputProcessor
{
public abstract ProcessInputsResult ProcessInputs(Item[] inputs);
}
interface IComponentContainer<T> where T : MachineComponent
{
public T[] Components { get; }
}
class MachineSystem : MachineComponent, IComponentContainer<MachineComponent>
{
public MachineComponent[] Components { get; }
}
我的目标是在
ProcessInputs
接口内提供 IComponentContainer
的实现,因为所有组件容器都必须处理其每个组件的输入,并且其实现可以在派生类之间共享。
为了实现这一点,我尝试在
ProcessInputs
内部为 IComponentContainer
创建一个默认方法实现,如下所示:
interface IComponentContainer<T> : IInputProcessor where T : MachineComponent
{
public T[] Components { get; }
ProcessInputsResult IInputProcessor.ProcessInputs(Item[] inputs)
{
...
}
}
请注意,我还如何使
IComponentContainer
派生自 IInputProcessor
,因为所有组件容器都必须处理其所有组件的输入。
我希望这个新定义意味着
MachineSystem
(既是MachineComponent
又是IComponentContainer<MachineComponent>
)不需要指定MachineComponent.ProcessInputs
的实现,因为这是在IComponentContainer
接口中给出的.
事实并非如此,我必须明确地将方法引用到接口中给出的实现,如下所示:
class MachineSystem : MachineComponent, IComponentContainer<MachineComponent>
{
...
public override ProcessInputsResult ProcessInputs(Item[] inputs) =>
((IComponentContainer<MachineComponent>)this).ProcessInputs(inputs);
}
我认为这违背了在接口中提供默认实现的目的,因为派生类必须指定它们想要使用。
这个问题有好的解决方案吗,还是应该改变代码结构?
我认为这违背了提供默认值的目的 接口中的实现作为派生类必须指定 他们想要使用的。
派生(或接口实现)类不需要指定任何内容,如果它们没有抽象类让它们这样做。
你定义了这样一个类
abstract class MachineComponent : IInputProcessor
{
public abstract ProcessInputsResult ProcessInputs(Item[] inputs);
}
现在所有派生类(如果不是抽象类本身)都需要重写该方法,从而提供一个实现,该实现将同时隐藏/优先于接口的默认接口实现。
这实际上甚至会阻止您的解决方法发挥作用
public override ProcessInputsResult ProcessInputs(Item[] inputs) =>
((IComponentContainer<MachineComponent>)this).ProcessInputs(inputs);
此强制转换方法调用编译为以下 IL:
callvirt instance class ProcessInputsResult IInputProcessor::ProcessInputs(class Item[])
因此,我们从
IInputProcessor::ProcessInputs
最具体/派生的实现中对 IInputProcessor::ProcessInputs
进行虚拟调用。换句话说,我们有无限的递归。
这使我们认识到,我们不能在应该重写的方法中重用默认接口实现,就像在类继承中的虚拟重写方法中调用
base.BaseClassMethod
一样。
我的目标是在内部提供 ProcessInputs 的实现 IComponentContainer 接口,因为所有组件容器都必须 处理每个组件的输入,以及实现 因为这可以在派生类之间共享。
我认为通过将
IComponentContainer<T>
作为抽象类,你可以解决大部分(如果不是全部)问题:
abstract class ComponentContainer<T> : MachineComponent where T : MachineComponent {
public T[] Components { get; }
public override ProcessInputsResult ProcessInputs(Item[] inputs) {
// implementation - will server for interface dispatch too
}
}
class MachineSystem : ComponentContainer<MachineComponent> {
// no need for anything here...we inherit from abstract class
}