A conventional approach (i.e. an approach that adheres to conventions found in the CLR and elsewhere) would be to use the built-in interfaces that represent collections, e.g. IList<T> or ICollection<T>.
public interface IGeoEntityCollection<T> : ICollection<T> where T : GeoEntity
public class GeoEntityCollection<T> : ...
This is one thing that annoys me about OOP design. People think they can have these debates looking just at the interface, when there is a clear winner when you look at the actual implementation.
There are a few big reasons why the convention is for the collection class to own modifications to the collection:
The collection owns the physical memory holding ...
I think you are asking the wrong question, since you expect to find a braindead general design rule which tells you if this kind of design is "good" or "object oriented" (whatever that means). I doubt there is such a rule. Better starting thinking about the specific case and ask if the design can be improved to achieve some specific goals,...
Unfortunately, nearly all languages allow for runtime loading of code and/or reflection which make full static analysis impossible because the code could be used dynamically. Though those tools exist for most languages if you’re willing to live with that caveat - not a few languages/IDEs do this sort of dead code/reference analysis these days and emit ...
In this specific case, it sounds like you just need a post-processing hook.
In its simplest form, it could look like this:
protected virtual void PostProcess()
//No code, do nothing
public void Run()
//Do Task 1
//Do Task 2
class A : BaseClass