Simply put they allow you to easily write asynchronous programs. Without you ever having to reorganize your code. Which can lead to massive performances increases.
The “async” & “Await” markers are keywords that mark the beginning and end of asynchronous code. Where “async” is put right before a function name, and “await” is put right before calling the function. However if a method is async then it needs to return a Task object.
Now you can use different parts of Task Asynchronous Programming (TAP) model. Such as start a bunch of tasks, and wait for them to finish. Or even call a new task on the completion of another task. All while your main application is running.
How is this possible ? Does it start a bunch of new threads ? Yes and No. If you start a bunch of tasks and wait for them to complete then yes. Where as if you await a heavy task it cuts up everything happening in our program the second it hits an await keyword. And starts executing everything based on the time available on the current thread. So you aren’t able to tell that your programming is waiting around for something.
What is the root object in the base class library ?
For Java and C# that would be “Object”.
What methods does “Object” have ?
- Equals – Supports comparisons between two objects
- Finalize – Used to perform cleanup operations on un-managed resources being used by the object. Before the object is destroyed.
- GetHashCode – Generates a number based on the value of an object. Used to supported hash tables.
- ToString – Create a human readable piece of text that describes the object.
Is “String” mutable ?
For C# & Java: Strings are always IMMUTABLE
What is Boxing and Un Boxing ?
Process of converting a value type to the type of object or any interface type implemented by this value type. Like storing int in a object which would be “Boxing” (implicit aka do it with out thinking about it). And then taking that object, and “Un-Boxing” it explicitly. Example of this would be something like “int i = (int)x” where x is type of object. Why would you ever want to do this ? Well that’s cause value types get stored in the stack, whereas reference types get stored in the heap. So if your running into performance problems by having a lot of value types floating around in the stack. You can just dump them into the heap, by boxing them.
D = Dependency Inversion Principle
This principle is about making sure you never have to rewrite your core logic. Meaning that if your class or piece of code has a dependency on something else. It should never access it directly. Instead it should go through some intermediary that abstracts the functionality away.
For example if your application talked to a database, you would’t want to be writing SQL statements directly into your code. Or if you were using a ORM (Object Relational Mapper) you would want queries every where. Especially if at some point you decide to move to another database type or ORM. To fix this problem you would need to create a wrapper around it, abstracting complex queries into simple common method calls. Like “Update User profile”, or “Set User Password”.
This way if you ever had to make any changes to the logic of how you accessed the database. You could do it with out changing any of your core application logic. Since your core application wouldn’t directly rely on how the method is implemented. This can also be thought of as always coding to a interface, rather then a direct implementation.
I = Interface Segregation Principle
This is all about separating your interfaces and making them smaller. Since we don’t want to end up having mega interfaces with a tons of properties, and methods, that may or may not be used by classes that implement them. If you don’t follow this principle you are probably gonna end up with a hair ball of OOP design. That will lead to harder refactors further down the line. For example lets say you have a “Entity” interface, that has properties “attackDamage”, “health”, and also has methods “move”, “attack”, and “takeDamage”. Now lets say classes “Player”, “Enemy” , “Chair”, and “MagicChest” implement it. Does this make sense ? Should the “Chair” class need to implement the “attack” method ? Most likely no it should not, but then it does need the “name” property. So we can factor out the common piece among the classes that implement “Entity”. So instead of just having the “Entity” interface. We can have a “BaseEntity”, “ActorEntity” and “StaticObject” interface. This way we won’t have any unnecessary implementations for any of the classes that implement the interfaces.
L = Liskov Substitution Principle
This is all about using Object Oriented Programming to its fullest. So what the Wikipedia article says is that: “If S is a sub-type of T then objects of type T maybe replaced with type S”. So what does that mean ?
Well it means that when you create your class hierarchy, and you create your base methods, you have to think about the broader implications. For example if your root parent class was “Bird” it would have methods like “Fly” , “Eat” and “Walk”. And then you would classes like “Hawk” , “Blue Jay”, “Robin”, “Penguin”, and “Ostrich”. Now we should be able to put any of these child classes in place of the parent class, and use them. Can you see the problem ?
The problem is that Penguins and Ostriches can’t fly, which violates the “Liskov Substitution Principle”. You can get around this by instead having the two different children inherit from the “Bird” class: “FlyingBird” and “NonFlyingBird”.
O = Open/Closed Principle
This is all about being “open for extension but closed for modification”. Your code should be extendable. To the point where you don’t need to constantly change anything about it. This can come in many forms; for example instead of overloading a class with a number of different methods. Such as the “Person” class needing a method like “write a book” and also like “fight a fire”, or even “cook a five star meal”. Instead we could separate these into classes that all inherit from the “person” class. Which would allow use to write code to extend existing functionality. Without having us go in and make changes to the core logic of the person class.
Another example of this is when we are using a large “if – else” or “switch” statement. And we do things based on what input we get passed in. Instead of having this large “if -statement” we can refactor the logic back into the input we are are being passed in. If we had gotten a generic account class as an input. And we had to calculate their net-worth based on their account type. We should create classes for each account type, and store the calculation logic in them, rather then in the “if else” clauses.
In this series I am going to be going through each of the principles. Go about explaining them in as simple of a manner as possible.
S = Single Responsibility Principle
Anything inside your code that is parts (class, modules, etc) should only ever have one reason to change. For example if you had a Person class, then everything in that class should only do things related to person. A person class should have methods like “eat”, “sleep”, “play”, and etc. However a person should never need to have a “log” method, cause it has nothing to do with a person.