First of all what do you mean with API? A collection of dll for Rhino? A COM Api etc?
Always 1 (more are possible). In DotNet, namespaces are used to structure your code. A project namespace should be a well structured project tree. Use folders for each subnamespace. Or do you mean derivation depth?
It depends on the project size. You already have two, if one is a test project. But don’t create too many if not necessary. 3-4 binaries for medium sized projects plus 3-4 Testprojects, plus Installer etc. making 6 to 10 solutions to be quite common. If you deal with more then 1 repository, a common repository might be benefical as well. But keep your sub repro count low, source control (Git) becomes quite cumberstone then. For a GH Addin 1-3 dlls/gha exposed to the user are probaly realistic.
I don’t understand, each class in dotnet derivies from System.Object
Follow and understand SOLID.
Use Ioc/Di Container -> Its a central place for constructing and retreiving object instances. There are many great plugins for this. Microsoft recently integrated their own “ServiceLocator”. This way you don’t need to pass other objects from object to object and so forth. And it works well when Unittesting. You can easily replace with mocks, for instance a Database - object with a DataBaseMock - object
Write Unittest and force yourself to comment. Comment at least every public member. Give a rough explanation what it does and why
Sketch a software architecture and add it to the project documentation. It really helps others and an older yourself to understand what it does and how.
Since I want to create an api to learn a bit more about .net and how things are organized. I want to start from scratch before I am able to create something more complex related to Rhino or COM.
My initial idea is e.g.:
class LKW (System.Collection) #Funny that I know the German abbreviation word for this classification but not the English one
class PKW (System.Collection)
class Car (Vehicle)
class Truck (Vehicle)
class Buss (Vehicle)
class SUV (Car)
class Hatchback (Car)
class Estate (Car)
class Sedane (Car)
I assume an API should be organized like this going deeper and deeper to actual parts of the vehicles.
I think this is too advanced, and too much automation. The more automation the less you learn about the basis. My main goal creating this API is to learn. Perhaps later on I can mix the classes I create with RhinoCommon deriving from both my test api and RhinoCommon and thus providing geometry to my vehicles. At least this is what I understand now about how APIs work. It is possible I am totally wrong about this and the approach should not be this at all
I saw you are recently promoting this unittesting a lot, and read a little about it. I believe this is for when I get a little bit more fluent. There are still a lot of things about C# that I do not understand.
Are you fluent enough to run your code and check whether it is running properly? Unit testing on small elements of code and integration testing on whole sections is simply doing this in a structured, repeatable manner.
There are also Unittesting frameworks for CPython!
All you need to to do is to create a test project, and test your functionality method by method. Testing frameworks usually give you the ability to assert.
expected_result = "I don't know"
my_name = 'Ivelin'
returned_result = my_awesome_lib.answer_to_life(my_name) #returns 42
assert.are_equal(expected_result,returned_result ) # will fail -> test will not pass
=> now a unittest framework usually gives you visual feedback.
The reason -> you can test multiple input cases and validate your functionality. This way you can easily test extreme input. The main advantage however is if you change your code later on, you know if it breaked something somewhere else. So when you move on with your code, you don’t need to repeat your tests manually again and again. You eliminate many bugs beforehand.
Just as a side note. The use of ioc container esp. the ServiceLocator Pattern may not be well suited for Apis, since it hides Dependencies. I completely missed that out. But within a closed application or not publicly exposed library functionality, I really like the pattern. Its also criticized by some people, but it is one of the most simple ways in structuring code!
Currently, I have the dilemma what are the differences between Interface and Abstract Class. Do I start the api by creating just Interfaces and then create Abstract Classes that derive from multiple interfaces. Or start by creating just Abstract Classes? How do one make a choice? Say you have a clear idea of an object with all the methods it has to have how do you decide if it has to be an interface or abstract class?
Another thing is what criteria to use when creating the folder structure of my project? How to arrange my class.cs files?
These kind of questions I was looking for when I started this thread.
I started reading the article from the link from @piac, but there aren’t any guides regarding this.
You use Abstract classes if you want to derive multiple objects from one base. GeometryBase -> Curve, or Surface or Mesh. GeometryBase holds variables and methods which all 3 childs share.
An interface allows you to “connect” objects quite loose (by Contract). You don’t care about the implementation but instead you say, whatever you are and whatever you do, if you implement this interface you guarantee that all functionality exposed in the Interface is callable. Interface can be used similar to an Abstract Base class, but you shouldn’t. You rather create interfaces based on features. Any object implementing the IDisposable interface owns a Dispose method which cares about cleaning up the object because the garbage collection can’t do for those objects. Another famous interface is the IEnumerable, which (if implemented) say this object contains multiple members which are iterable. For instance a collection like a List and Array share this. Another more CAD related Interface could be a fictive IExportable, which describes an object which can be exported and therefore contains an Export method. Since any object can implement more Interfaces, it could also implement an IImportable which guarantees this object contains a Import method for instance. There are more advantages to interfaces esp. regarding software patterns, but this will extend that reply by far. But interfaces are no objects, they are blueprints of functionality. Abstract classes in comparison can be instanciated but the abstract keyword say that this won’t make any sense. I mean, what would an GeometryBase instance do?
If I understand correctly interfaces simply add some methods if a class is derived from them. But is the Abstract Class derived from multiple interfaces or a class that derives from an abstract class also derived from an interface?
A few more questions:
In the above example about vehicles. I assume the abstract class will be e.g. Abstract Class Vehicle. Then are the Class Trucks and Class Cars supposed to be Abstract again?
I see Interfaces are set a name of an ability: IEnumerable, IDisposable,IExportable, etc. So I guess the Abstract Class Vehicle should derive from a number of interfaces: IMovable, ILoadable (for fuel), IUnloadable(for fuel), IFuelConsuming, ISteerable, etc. Is that meaningful?
Sure you can derive an abstract class from an abstract class and so forth. Derivation depth is not bound
But any object can only derive from one (abstract) class. So polymorphism is not allowed in C#
Abstract just means its an class which does not makes sense to initiate. You don‘t need to use the abstract keyword, but someone using your code immediately knows that (I mean its actually obvious) a car, truck or vehicle are not classes to initiate, whereas as Bugatti Chiron for instance is.
You don‘t need to create interfaces which follow no purpose later on, but dividing into multiple smaller interfaces follows the SOLID principles. The advantages, lets say you implement some concrete subclasses Vehicle-Car-Sportscar-BugattiChiron and a Vehicle-Car-Pickup-DogdeRam1500 which both implement the Interface IGasolineEngine and you also have third Class Vehicle-Car-Sportscar-BMWi8 which implements the IElectricEngine . Now at the other end of your application you create a „GasStation“ class which refuels only IGasolineEngine objects. If you later create complete different objects such as totally vehicle unrelated object like EmergencyPowerGenerator which also implements the IGasolineEngine you can take this object and „refuel“ it at your gasstation.
Might this example not be a little confusing to a newbie? I can’t immediately think of a commonplace situation where I would create a class specific to a vehicle model. I would create, say, Vehicle-Car-Sportscar and instantiate an object, BugattiChiron, of that class. I could then easily instantiate an MGB and whatever other sportscars I wanted. I don’t see that there would be sufficient differences between sportscars’ attributes and methods to warrant further subdivision. What do you think?
That’s a design decision. I doubt you would do that, but it depends on what your system is intended to do.
The workflow is to start by eliciting requirements (“As a garage owner I need to find a pickup with V8 power”), then analyse what a system has to do to meet (at least some of) the requirements (“We need to classify vehicles by use”, “we need to distinguish power sources”), then design a software model that delivers the functionality (“We need an abstract vehicle class”, “we need a utility vehicle sub-class”, “the vehicle class will have an attribute Engine of type EngineClass”, the utility vehicle class will have an attribute LoadCapacity"), finishing up with coding.
In designing our classes we look to include the attributes and methods that are common to the class (vehicle.wheelCount, vehicle.topSpeed, vehicle.startEngine()). We create a sub-class only where the information content or activity of a vehicle is specialised to that sub-class only (utility.loadCapacity). Ideally we want our classes to be as general as possible, because too many classes make program maintenance harder.
The important thing is to follow the workflow so you have a rationale for your design decisions. That workflow, incidentally is cyclical, you keep going round to refine, extend and improve.