覆盖接口方法但使用派生类的参数
c#
我想创建一个服务结构,所有这些服务都源自IService具有唯一方法的接口Perform
为了允许派生类定义特定 Perform 实现需要的参数类型,我将这些参数封装在一个名为的接口中 IConfig
问题是我无法访问自定义 Perform 实现中的派生类属性,因为我被迫键入将参数为IConfig
有什么方法可以用接口方法的参数类的派生类的参数覆盖接口/抽象类方法吗?
例子:
interface IConfig {}
class Config : IConfig
{
public int Property;
}
interface IService
{
void Perform(IConfig config);
}
class Service : IService
{
void IService.Perform(IConfig config)
{
config.Property;
}
}
通过上面的Service实现,我得到了错误:
“IConfig”不包含“属性”的定义
如果我把它改成这样:
class Service : IService
{
void IService.Perform(Config config)
{
config.Property;
}
}
我收到错误:
'Service' 没有实现接口成员 'IService.Perform(IConfig)'
和
在可实现的接口成员中找不到显式接口声明中的“Service.Perform(Config)”
我想知道是否有类似的东西:
void IService.Perform((IConfig)Config config)
或者
void IService.Perform(Config config as IConfig)
或者
(Config)config.Property
回答
使用泛型
这是使用泛型的完美案例。
interface IConfig { }
class Config : IConfig
{
public int Property;
}
interface IService<T> where T : IConfig
{
void Perform(T config);
}
class Service : IService<Config>
{
public void Perform(Config config)
{
config.Property;
}
}
泛型参考 - https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
where参考 - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
请注意,通过使类或接口泛型,您不能将其简化为非泛型形式,例如IService不更改它,以便泛型形式从非泛型基础扩展,如下所示:
interface IService
{
}
interface IService<T> : IService where T : IConfig
{
void Perform(T config);
}
这在强制转换为时移除了对泛型表单属性的访问IService(这在您考虑时很明显)。您必须将其转换回其正确的泛型类型 ( IService<Config>) 才能访问那些在处理List<IService>多个泛型类型的集合(例如)时可能会引起头痛的属性。
为了避免这种情况,您可以满足于使用简单的铸造。
使用铸造
如果您不关心对配置类型的编译时限制,并且确实关心上述List<IService>问题,则可以选择运行时替代方案,如下所示:
interface IConfig { }
class Config : IConfig
{
public int Property;
}
interface IService
{
void Perform(IConfig config);
}
class Service : IService
{
void IService.Perform(IConfig config)
{
if (!(config is Config)) throw new ArgumentException("Expected config to be of type Config");
Config castedConfig = (Config)config;
castedConfig.Property;
}
}
这不会阻止您Perform通过编译时限制使用不正确类型的配置进行调用,但是ArgumentException如果您确实使用不正确类型的配置调用它,它会在运行时抛出一个。