简体   繁体   中英

Override an interface method but using argument of a derived class

I want to create a structure of Services all of them derived from the interface IService which has an only method Perform

In order to allow the derived classes to define the kind of arguments the specific Perform implementations need I encapsulate such arguments in an interface called IConfig

The problem is that I can not access to the derived class properties in my custom Perform implementations because I am forced to type the argument as IConfig

Is there any way I can override an interface/abstract class method with arguments of derived class of the interface's method's argument's class?

Example:

interface IConfig {}

class Config : IConfig
{
    public int Property;
}

interface IService
{
    void Perform(IConfig config);
}

class Service : IService
{
    void IService.Perform(IConfig config)
    {
        config.Property;
    }
}

With the above Service implementation I get the error:

'IConfig' does not contain a definition for 'Property'

If I change it to this:

class Service : IService
{
    void IService.Perform(Config config)
    {
        config.Property;
    }
}

I get the errors:

'Service' does not implement interface member 'IService.Perform(IConfig)'

and

'Service.Perform(Config)' in explicit interface declaration is not found among members of the interface that can be implemented

I am wondering if there is something like:

void IService.Perform((IConfig)Config config)

or

void IService.Perform(Config config as IConfig)

or

(Config)config.Property

Using generics

This is the perfect case for using generics.

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;
    }
}

Generics reference - https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/

where reference - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint


Be aware by making a class or interface generic you cannot reduce it to a non-generic form like IService without changing it so that the generic form extends from a non-generic base like so:

interface IService
{

}

interface IService<T> : IService where T : IConfig
{
    void Perform(T config);
}

This removes the access to the properties of the generic form when cast to IService (which is obvious when you think about it). You'll have to cast it back to its correct generic type ( IService<Config> ) to access those properties which might cause a headache when dealing with collections ( List<IService> for example) of multiple generic types.

To avoid this you can settle for using simple casting.

Using casting

If you don't care about compile-time restrictions on the type of the config and you DO care about the List<IService> problem above, you can go for a run-time alternative like so:

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;
    }
}

This will NOT prevent you from calling Perform with a config of the incorrect type through compile-time restrictions but it WILL throw an ArgumentException on run-time if you do call it with a config of the incorrect type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM