How to differentiate a Virtual Method that should be Augmented vs. Replaced? #5866
-
I write two main types of Virtual Methods in a base class (often abstract).
What is the correct/best way to differentiate between the two, aside from a comment. And the comment-method is problematic, because the Summary is supposed to tell you "how to use the method" not "how to override it". So this has always been a bit of conundrum that I've seen, dealing with this ambiguity. I wish there were a keyword to put in the base definition like "protected virtual extended void MethodName()" to signify a method that should be called by the overrides. And then if the override method calls or doesn't call the base method, the compiler will issue a Warning (or error?) - to prevent the mistake. Example: |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 27 replies
-
This would be a space for analyzers for your domain-specific additional rules you would like to have. That said, the way i generally handle this is to never make it necessary for the override to call into the base. Indeed, anything that must run is designed to be impossible not to run. The override only exists for the part that is ok to be overridden without the base happening. In other words. INstead of:
I instead write:
Now there's no problem. The subclass can't mess this up, because calling into the base is not necessary. |
Beta Was this translation helpful? Give feedback.
-
NEVERMIND -- just looked it up -- "sealed" is ALREADY a thing for preventing the propagation of overrides. IGNORE THIS QUESTION: |
Beta Was this translation helpful? Give feedback.
-
For case of making my concerns more clear. Here is an example of work arounds that I've done in the past: public void Update(float timeStep)
{
// Core non-optional logic that must run goes here ....
// .....
OnUpdate();
}
virtual protected void OnUpdate() { } // does NOTHING unless overridden Here, those who write derived classes will see BOTH "Update" and "OnUpdate", and may call the wrong one. We've introduced more ways to mess up, and more thinking for the dev to do -- for no good reason, other than a C# deficiency in allowing the base class author to specify usage rules. What I'd prefer to write is this: public virtual mustCallFirst void Update(float timeStep)
{
// Core non-optional logic that must run goes here ....
// .....
} This shorter code snippet produces the SAME effect, forcing the override to call the base method first, and requires no additional class member to enforce it. This added syntax puts control on usage where it belongs - with the author of the base class, without forcing the addition of "similar named" members to create the same effect. |
Beta Was this translation helpful? Give feedback.
-
I'd add to this proposal, specifiers that should even limit "who can call a method". If for some reason I do still need to create a pattern like this: (introducing combo term "protected private") public void Update(float timeStep)
{
_OnBeforeUpdate();
// Core non-optional logic that must run goes here ....
// .....
_OnAfterUpdate();
}
virtual protected private void _OnBeforeUpdate() { } // does NOTHING unless overridden
virtual protected private void _OnAfterUpdate() { } // does NOTHING unless overridden In the above example, I've introduced a suggested notation of "protected private" -- which means "you can ONLY OVERRIDE this method" -- you cannot CALL this method from a derived class (because it is ONLY intended to be called by the "Update()" method -- no one else. This highlights another issue with the @CyrusNajmabadi (and my) methodology of creating an extra member to help prevent "misuse" -- we are now opening up another potential defect, in that people can call the wrong method, when they should NEVER be allowed to CALL this other method (only override it). C# does NOT provide enough "control/prescription on usage" of it's protected methods, nor for it's virtual methods. This is worth serious discussion. |
Beta Was this translation helpful? Give feedback.
-
I added a new Language Idea here, for y'all to shoot down. Enjoy. |
Beta Was this translation helpful? Give feedback.
This would be a space for analyzers for your domain-specific additional rules you would like to have.
That said, the way i generally handle this is to never make it necessary for the override to call into the base. Indeed, anything that must run is designed to be impossible not to run. The override only exists for the part that is ok to be overridden without the base happening.
In other words. INstead of:
I instead write: