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
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.
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.