protected abstract override Foo(); – er... what?
- by Muljadi Budiman
A couple of weeks back, a co-worker was pondering a situation he was facing. He was looking at the following class hierarchy: abstract class OriginalBase
{
protected virtual void Test()
{
}
}
abstract class SecondaryBase : OriginalBase
{
}
class FirstConcrete : SecondaryBase
{
}
class SecondConcrete : SecondaryBase
{
}
Basically, the first 2 classes are abstract classes, but the OriginalBase class has Test implemented as a virtual method. What he needed was to force concrete class implementations to provide a proper body for the Test method, but he can’t do mark the method as abstract since it is already implemented in the OriginalBase class.
One way to solve this is to hide the original implementation and then force further derived classes to properly implemented another method that will replace it. The code will look like the following:
abstract class OriginalBase
{
protected virtual void Test()
{
}
}
abstract class SecondaryBase : OriginalBase
{
protected sealed override void Test()
{
Test2();
}
protected abstract void Test2();
}
class FirstConcrete : SecondaryBase
{
// Have to override Test2 here
}
class SecondConcrete : SecondaryBase
{
// Have to override Test2 here
}
With the above code, SecondaryBase class will seal the Test method so it can no longer be overridden. Then it also made an abstract method Test2 available, which will force the concrete classes to override and provide the proper implementation. Calling Test will properly call the proper Test2 implementation in each respective concrete classes.
I was wondering if there’s a way to tell the compiler to treat the Test method in SecondaryBase as abstract, and apparently you can, by combining the abstract and override keywords. The code looks like the following:
abstract class OriginalBase
{
protected virtual void Test()
{
}
}
abstract class SecondaryBase : OriginalBase
{
protected abstract override void Test();
}
class FirstConcrete : SecondaryBase
{
// Have to override Test here
}
class SecondConcrete : SecondaryBase
{
// Have to override Test here
}
The method signature makes it look a bit funky, because most people will treat the override keyword to mean you then need to provide the implementation as well, but the effect is exactly as we desired. The concepts are still valid: you’re overriding the Test method from its original implementation in the OriginalBase class, but you don’t want to implement it, rather you want to classes that derive from SecondaryBase to provide the proper implementation, so you also make it as an abstract method.
I don’t think I’ve ever seen this before in the wild, so it was pretty neat to find that the compiler does support this case.