In Ctrl: C# Constructors, /this/ Keyword And Namespaces
Sep 19th 2020In my previous C# post, I explained some core concepts of object-oriented programming and I, with much respect, suggest you read that post before delving into this one to cut yourself some trouble.
Constructors
Straight to the business. A constructor in C# is just a method. I assume you're already familiar with methods and have written some of them yourself. A constructor method's main purpose is to initialize an object's variables. As we already know, an object in C# and many other languages is able to know some things about itself right out of the bat. The things it knows about itself are variables and some like calling them instance variables because essentially they vary in instances. Let's say we've got a Shape class and using it we've initialized two objects - greenTriangle and goldenHexagon. Their number of vertices and color are different because their respective instance variables (e.g, greenTriangle.color, goldenHexagon.numberOfVertices) have different values. A constructor inside a class is used to establish these instance variables upon creating an object. Since constructors are methods, the syntax is very similar, but here you don't have to specify return type. You have to, however, use the same identifier (name) for both - class and its constructor like so:
SuperCar.cs
class SuperCar{
public string brand;
public string model;
public string releaseYear;
public double torque;
public double engineSpeed;
private double horsePower;
// Constructor incoming
public SuperCar(string par1, string par2, string par3, double par4, double par5){
brand = par1;
model = par2;
releaseYear = par3;
torque = par4;
engineSpeed = par5;
}
public double HorsePower(){
horsePower = (engineSpeed * torque) / 5252;
return horsePower;
}
}
Now let's initialize some objects...
Program.cs
using System;
class Program{
SuperCar fordGT = new SuperCar("Ford", "GT", "2005", 678, 6500);
double ford_gt_horsepower = fordGT.HorsePower();
SuperCar bmw_m1 = new SuperCar("BMW", "M1", "1980", 330, 6500);
double bmw_m1_horsepower = bmw_m1.HorsePower();
}
Do you see what the constructor is doing right there? Now, as opposed to examples from the previous post, upon creation objects require you to fill out some parameters and those being the object's instance variables. As you can see, I hardcoded values in, but you can really go bonkers with this by passing in dynamic content such as data from some database. You might've noticed some seemingly nonsensical code in SuperCar.cs
:
SuperCar.cs
class SuperCar{
// ...
public SuperCar(string par1, string par2, string par3, double par4, double par5){
// ...
}
// ....
}
this Keyword
Those variable names are disturbing and confusing, which is why C# syntax bestowed us the permission of using the same names for both - instance variables and local variables, only with one condition, though, that being, we ought to use the this
keyword in such a case. The actual value of this
is an address of the object and whenever we use it, we get back to the object's own scope rather than, say, a method's scope. We're required to use this keyword, because whenever an instance variable and a parameter of a method have one same identifier, what matters the most is the scope. Let's say, you and your friend are watching a football match. Your friend's name is Joe. There's also Joe on the pitch, playing as a goalie for Manchester City. Both - your friend Joe and Joe the goalie are within the stadium territory (scope), and suddenly, just the name Joe no longer matters on its own for one of the two. You've now got to specify which Joe you are talking about, you have to specify the scope. The this
keyword is used to differentiate between same-identifier-different-scope variables. Let's take this idea for a spin:
SuperCar.cs
class SuperCar{
public string brand;
public string model;
public string releaseYear;
public double torque;
public double engineSpeed;
private double horsePower;
// Constructor incoming
public SuperCar(string brand, string model, string releaseYear, double torque, double engineSpeed){
this.brand = brand; // Instance variable this.brand now equals to parameter brand
this.model = model; // Same syntax for all identical names
this.releaseYear = releaseYear;
this.torque = torque;
this.engineSpeed = engineSpeed;
}
public double HorsePower(){
horsePower = (engineSpeed * torque) / 5252;
return horsePower;
}
}
As you can see, I changed parameter names in SuperCar()
constructor to something more comprehensive and prefixed all matching instance variable identifiers with this
keyword. There's no need for this
in the HorsePower()
method, as there's no conflict between parameters and instance variables, so we can leave the horsePower
, engineSpeed
and torque
variables as is, without this
keyword.
Namespaces
Namespaces are used to abolish conflict between class names. You know, in class Car{}
, Car is the class name. Let's say you've been working with other programmers. You need to create a class called Door, but someone else has already done that, so there's already a class with that name. Are you going to rename your class just like that? You can create a Namespace for yourself and do whatever the hell you want instead. In a namespace, you can declare names at will, without the worry of them being in conflict with already existing ones, as they'll end up outside your namespace anyways. Let's create a separate C# code file for namespaces only and add two - Ford
and Ferrari
.
Namespaces.cs
// There's a lot of stuff declared in System namespace. One of them being Console,
// With which we log stuff.
using System;
// Namespace for Ford classes
namespace Ford {
// ...
public class SuperCar{
public string brand;
public string model;
public string releaseYear;
// Constructor incoming
public SuperCar(string brand, string model, string releaseYear){
this.brand = brand;
this.model = model;
this.releaseYear = releaseYear;
}
public void CarSalesman(){
Console.WriteLine("This bad boy (slaps car) is " + brand +
" " + model + " from " + releaseYear);
}
}
// ...
}
// Namespace for Ferrari classes
namespace Ferrari {
// ...
public class SuperCar{
public string brand;
public string model;
public string releaseYear;
// Constructor incoming
public SuperCar(string brand, string model, string releaseYear){
this.brand = brand;
this.model = model;
this.releaseYear = releaseYear;
}
public void CarSalesman(){
Console.WriteLine("Questo ragazzaccio (schiaffeggia la macchina) è " + brand +
" " + model + " a partire dal " + releaseYear);
}
}
// ...
}
Despite the fact that there was already a SuperCar
class somewhere in our code, I still proceeded to make the other 2 with the same exact name, but we've placed them in different namespaces, so it's no problem. Let's see how we can reach the new classes from our driver code file Program.cs
because the syntax is a little bit different in a way that we'll now have to specify the namespace before class name. Also, remember that whenever we want to use certan namespace in a file, we have to say that we're using
it:
Program.cs
using System;
using Ford; // See how we 'import' namespaces?
using Ferrari;
class SuperCar{
// The earlier class that we created. It belongs to global namespace,
// which is declared upon creation of project. So, no prefix means global namespace.
SuperCar bmw_m1 = new SuperCar("BMW", "M1", "1980", 330, 6500);
double bmw_m1_horsepower = bmw_m1.HorsePower();
// This SuperCar class belongs to Ford namespace, so we prefix it with Ford.
Ford.SuperCar ford_mustang = new Ford.SuperCar("Ford", "Mustang", "2004");
ford_mustang.CarSalesman();
// This SuperCar class belongs to Ferrari namespace, so we prefix it with Ferrari.
Ferrari.SuperCar ferrari_testarossa = new Ferrari.SuperCar("Ferrari", "Testarossa", "1984");
ferrari_testarossa.CarSalesman();
// Watch Ford v Ferrari
}