I have spent my last 3 years working on Plainconcepts in an amazing project called WaveEngine, this is a 2D/3D multiplatform game engine. And I learn a lot of things by working on this project, because I think it is very different develop apps using some libraries or frameworks than to develop a library or a framework for others developers who will later create apps using it. The first thing is that your customer are developer intead of final user and developer are very demanding with the libraries that they use (representative names of methods, intellisense documentation, clean API, consistency are some examples).
So when you work on a library, you sometimes need to hide some parts of your API like methods or properties which you don’t want the final developers to have access to or to change directly, or simply because you want to offer a clean API to these final developers. I would like to show you some techniques to get this behavior.
Using visibility operators like internal or protected internal
We need to have a Game class with a Draw method, which will be called from the main loop of our graphics framework. If our graphics framework needs to synchronize some methods or needs to prepare properties before calling the Draw method, to make it easier others task for our users we could make this method invisible in our API. Using internal this method will be accessible only from classes in the same assembly.
Draw method will be “public” for us from our assembly but invisible for our users.
Another possibility is if our users need to extend a framework class and override one of its methods, and we need to be able to call this new method from another class but we don’t want the final developer to call this method from another class.
We can call the ResolveDependencies method written for our user from other classes inside of our framework assembly, but for the final developer this method is only protected, so they can’t call this method from other classes in their code.
Using explicit interfaces implementation
Explicit interfaces implementation is a great technique in C# that allows us to clean our final API. This is the most common technique used by Microsoft in all their APIs. The situation is, imagine that you need some extra method to simplify the final API for users, but all this aux method blurred the final API.
So if you make an explicit implementation for these aux methods, those methods will only be visible if you do a casting to the specific type.
How to call each method:
When our user uses intellisense on the GameObject instance, they will only see the Play method (clean API), and if he does a casting to the interface then he could access all the methods from the specific interface.
Using new to override methods
Imagine this situation, we want to draw 3D and 2D elements, to do that we need to call the low level API in DirectX so that all is drawn using 3D vectors (a 2D sprite is a 3D plane oriented to the camera any Z plane). But the user wants a 2D simplified API that only shows them 2D vectors.
We are going to create a base class Transform3D where we have all the properties needed to draw 3d models, plus we will have a Transform2D class with some helper methods and with some extra properties like zoom or flip options.
Internally you need all transform3D properties to be able to render the 2D elements, but your users want to see a simple API with only 2D vector properties. To solve this situation we will use the new keyword to override some methods and properties.
Using this technique our user will only see the 2D LocalPosition property version from Transform2D and to access to the 3D LocalPosition property version they will need to do a casting to Transform3D like this:
It is important to remember that the purpose of all these techniques are only simplify the final API for the developers who use your libraries or frameworks.
I hope you enjoyed reading this post XD