I have an abstract base class that will be used in hundreds of derived classes, including an additional abstract class.
There are at least 2 properties (let's call them Purpose and Description, both strings) that will be added to many (but not all) of the concrete derived classes, so I created interfaces (IPurposeful and IDescribable) to add them when needed. All is well so far.
I want a single method that I can call on all classes derived from my base class that will validate and update the Description property if it is indeed IDescribable, or just return true if it is not IDescribable. I'd like another similar method to validate/update the Purpose property.
I achieve this with a method in the base class that looks something like this:
protected bool CheckDescription(bool modify = false)
{
if (this is IDescribable ele)
{
var newDesc = GetCorrectDescription();
UpdateDescription(newDesc, ele.Description, modify);
return newDesc.Equals(ele.Description);
}
else
{
return true;
}
}
SonarQube marks the "this is IDescribable" check as a blocker (bad practice) and I am wondering why? The only other way I can think of to replicate this functionality would be to change the base method to this:
protected virtual bool CheckDescription(bool modify = false)
{
return true;
}
and then add this exact same method to potentially hundreds of derived classes:
protected override bool CheckDescription(bool modify = false)
{
var newDesc = GetCorrectDescription();
UpdateDescription(newDesc, Description, modify);
return newDesc.Equals(Description);
}
Now THAT would seem like bad practice.
EDIT: Changed the is/as pattern to remove redundancy
I decided to explore extension methods a bit more and found that for my particular needs they will work fine. I wanted to mark the original suggestion to look at extension methods as the correct answer but cannot seem to find a mechanism to do so.
Anyway, extension methods fulfill my requirements to be able to define a default algorithm in one place for most derived classes and override that behavior in specific derived classes only if/when necessary.
The one downside is that I cannot call the "base" implementation from within the "override" method. This may lead to a need to duplicate code in the future but thankfully for now I have not had that problem.