Introduction to C#Your first C# app

I'll suppose that you already have some programming knowledge of an object oriented language like C++ or Java. Here you'll find some of the basics of C# compared to these two languages for an easier assimilation. It does not pretend to be exhaustive, you can find far more detailed comparisons in C# for Java Developers and C# for C++ Developers.

Brief comparison between Java, C++ and C#
Java C++ C#
Imports import java.lang.Math.*; #include <cmath> using System.Math;
Name space package ParentDir.ChildDir; // Also ParentDir.ChildDir.function(){} using namespace std; // Also using namespace myNamespace { function(){} } myNamespace::function(){} namespace ParentDir.ChildDir {}
Constants private static final double PI = 3.14159; //initialized at compiling time const double pi = 3.14159; //happens before the program is compiled #define PI 3.14159 //initialized at compiling time private const int PI = 3.14159; //initialized at run time private readonly int ID;
SD Output System.out.println("Text " + variable); cout << "Text " << variable << endl; Console.WriteLine("Text {0}", variable);
SD Input Scanner sc = new Scanner(System.in); int i = sc.nextInt(); cin >> i; i = Console.Read();
Arrays int[] x = new int[10]; int[][] y = new int[2][3]; int x [3] = {1, 2, 3}; int y[2][3] = { {1, 2, 3}, {1, 2, 3} }; int[] x = new int[10]; int[,] y = new int[2,3];
Classes in Java, C++ and C#
Java C++ C#
Inheritance public class Child extends Parent {} class Child: public Parent {} public class Child : Parent {}
Constructors public Parent() { } public Parent(int parameter1) { this.parameter1 = parameter1; } /* CHILD CONSTRUCTORS */ public Child() { super(); } public Child(int parameter1) { super(parameter1); } public Child(int parameter1, int parameter2) { super(parameter1); this.parameter2 = parameter2; } public Parent() { } public Parent(int parameter1) { this.parameter1 = parameter1; } // "this" calls the constructor of the child // "base" calls the constructor of the parent public Child(int id) : this(id, false) { } public Child(int parameter1) : base(parameter1){ this.parameter2 = parameter2; } public Child(int id, int parameter1) : base(parameter1){ this.id = id; this.parameter2 = parameter2; }
Method overloading //Happens at compiling time public void accelerate() {} public void accelerate(int increment) {} public void accelerate(double newaccvalue) {} public: { void accelerate() {} void accelerate(int increment) {} void accelerate(double newaccvalue) {} } public void accelerate() {} public void accelerate(int increment) {} public void accelerate(double newaccvalue) {}
Method overriding //happens at run time public class Parent { public int someMethod() { return 3; } } public class Child extends Parent { public int someMethod() { return 4; } } class Parent { public: int someMethod() { return 3; } }; class Child : public Parent { public: int someMethod() { return 4; } } public class Parent { public int someMethod() { return 3; } } public class Child : Parent { public int someMethod() { return 4; } }
Method extension public class Parent { public void printMethod() { System.out.println("Printed in Parent."); } } public class Child extends Parent { public void printMethod() { super.printMethod(); System.out.println("Printed in Subclass"); } } (happens at run time) public class Parent { public void printMethod() { Console.WriteLine("Printed in Parent."); } } public class Child : Parent { public void printMethod() : base() { Console.WriteLine("Printed in Parent."); } }

C# also has two new access modifiers, internal and protected internal:

  • Public: Visible to all.
  • Protected: Visible only from derived classes.
  • Private: Visible only within the given class.
  • Internal: Visible only within the same assembly.
  • Protected internal: Visible only to the current assembly or types derived from the containing class.

"Same assembly" means inside the same file. In Java, each class goes in its own file, and there can't be more than 1 class per file. In C#, you can have as many classes as you want inside the same file. If no identifier is used, all classes are internal by default.

Sample "Hello world" console application

Using some of the code in the tables above, and following the introductory guide, we could write something like this:


using System;

namespace HelloWorld {

	class Program {

		static void Main(string[] args) {

			// Create an array of words
			// the string type is all-lowercase
			string[] helloword  = new string[5];

			// Arrays start in 0
			// Strings are written in quotes
			helloword[0] = "This";
			helloword[1] = "is";
			helloword[2] = "my";
			helloword[3] = "first";
			helloword[4] = "C sharp app";

			// One way of looping through an array
			for (int i = 0; i<helloword.Length; i++) {
				Console.WriteLine(helloword[i] + " ");
			}
			Console.WriteLine();

			// Another way of looping through an array
			foreach (string s in helloword) {
				Console.WriteLine(s + " ");
			}
			Console.WriteLine();

			// The empty call to WriteLine inserts a return.
		}
	}
}
				

And the output will be:


This is my first C sharp app
This is my first C sharp app
				

Now go on and try to write your first C# application using all you have learned! Or click the big button to see an example.

Example: BattleStar Galactica

I propose a very simple console app inspired on the awesome science-fiction TV-show BattleStar Galactica. The application uses almost every concept mentioned above and requires very few interaction from the user. Basically, it creates some vipers (the good guys) and some Cylons (the bad guys) with a certain amount of life, and then they shoot at each other until one group dies.

Also: this is the first thing I ever made with C#! My Hello World =)

Download the example!

GitHub BitBucket GitLab

The classes

In C#, we can create our classes in the same file, so we create a Battleship class to define general attributes and methods for a ship, and then a Viper and CylonRaider classes that inherit from Battleship and implement their own particularities.

The common attribute for all spaceships is the amount of life, which can be zero but not negative. First, see how the attribute Life is defined. This is the way C# has of doing three things at the same time: declaring the variable, and defining the setter and getter. Also, the name of a variable defined this way starts with a capital letter. These are called "named attributes" or "read/write properties". Second, there are two constructors defined. One has no parameters, and assigns a "default" value of 10 for the Life attribute. To do this, it calls the other constructor, the one that accepts a parameter to set the value of the Life attribute. Thanks to the way we defined the variable and its setter and getter, updating or retrieving its value works as it would for a normal variable.

The common methods are Shoot(), which takes an array of "victim" battleships as parameter, and Receive(). Notice how their names start with a capital letter too, according to the Method naming guidelines (another difference with Java). Since these two methods can be overwritten by the derived classes Viper and CylonRaider, we add the virtual modifier.


/* *********************************************************
 * CLASS BATTLESHIP
 * *********************************************************/
class Battleship {

	// The special way C# has to define an attribute
	// as well as its setter and getter in one go:
	public int Life {
		get;
		set;
	}

	public Battleship() : this(10) {
	}

	public Battleship(int Life) {
		this.Life = Life;
	}

	virtual public void Shoot(Battleship[,] targets) {
		Random rnd     = new Random();
		Boolean found  = true;

		do {
			int i      = rnd.Next(0, targets.GetLength(0));
			int j      = rnd.Next(0, targets.GetLength(1));
			if (targets[i, j].Life > 0) {
				Console.Write("Hit!!");
				targets[i, j].Receive();
				found = false;
			}
		} while (found);
	}

	virtual public void Receive() {
		// Implemented by child classes
	}
}
						

The CylonRaider class inherits from this Battleship class, and defines its own extra method PrintSquadron() and an attribute ID, which is going to be readable but not writeable, and Vipers define two extra attributes. Both overwrite the parent method Receive().

Since these two classes inherit from Battleship, the name of the class adds a : Battleship call at the end, and the constructor adds a : base(Life). Then, from the constructor without parameters, (or with the extra parameters defined in the daughter classes), we make a call to the "real" constructor using : this(extra parameters, Life), just as we did before in Battleship. But now, the modifier makes more sense: this differentiates the call to the class constructor from the call to the inherited constructor.

The extra method PrintSquadron() is going to print the matrix of Cylons, showing how many of them are alive or dead.


/* *********************************************************
 * CLASS CylonRAIDER
 * *********************************************************/
class CylonRaider : Battleship {

	// Battery of spaceships
	public static int CylonRaiderCounter = 0;

	// Pilot and ship are one in CylonRaiders
	private readonly int ID;

	public CylonRaider(int ID) : this(ID, 5) {
	}

	public CylonRaider(int ID, int Life) : base(Life) {
		this.ID = ID;
		CylonRaiderCounter++;
	}

	public int getID() {
		return ID;
	}

	override public void Receive() {
		Life /= 2;
		Console.WriteLine(" Cylon {0}'s life reduced to {1}", ID, Life);
		if (Life <= 0) {
			CylonRaiderCounter--;
			Console.WriteLine("\tR. I. P. Cylon {0}", ID);
		}
	}

	public static void PrintSquadron(Battleship[,] squadron) {
		int col = 0;
		Console.Write("\n\t");
		foreach (CylonRaider ship in squadron) {
			if (ship.Life <= 0)
				Console.Write("X ");
			else
				Console.Write("C ");
				col++;
			if (col % 5 == 0)
				Console.Write("\n\n\t");
		}
	}
}

/* *********************************************************
 * CLASS VIPER
 * *********************************************************/
class Viper : Battleship {

	public static int viperCounter = 0;

	// Vipers may have many pilots
	public string Pilot {
		get;
		set;
	}

	public string PilotWarCry {
		get;
		set;
	}

	public Viper(string Pilot, string PilotWarCry) : this(Pilot, PilotWarCry, 10) {
	}

	public Viper(string Pilot, string PilotWarCry, int Life) : base(Life) {
		this.Pilot = Pilot;
		this.PilotWarCry = PilotWarCry;
		viperCounter++;
		Console.WriteLine("{0}, GO AHEAD!", Pilot);
	}

	override public void Receive() {
		Life /= 2;
		Console.WriteLine(" {0}'s life reduced to {1}", Pilot, Life);
		if (Life <= 0) {
			viperCounter--;
			Console.WriteLine("\tR. I. P. {0}", Pilot);
		}
	}
}
						

The main program

In the same file, we have the default Visual Studio class program, with the Main() method. We can define other methods too for this class. There are TypeWrite(), to write to the console letter by letter like in a science fiction movie, and Combat(), where the vipers and Cylon raiders are going to shoot each other.

Also, they don't need to be defined as static, if you don't want to get errors for calling non-static methods inside the static Main() method, all you have to do is create an instance of the Program class (inception, anybody?) and call the methods using that instance:


class Program {

	static void Main(string[] args) {

		Program p = new Program();

		p.TypeWrite()...
		p.Combat()...

		// etc.

		public void TypeWrite(string text) { ... }

		public int Combat(Battleship[,] CylonRaiderSquadron, Battleship[,] vipers) { ... }
						

The TypeWrite() method loops on every character inside the string provided as parameter, and types it in the console after a delay by the system function Sleep():


/*  *********************************************************
*                       METHOD TypeWrite
* *********************************************************/
public void TypeWrite(string text) {
	for (int i = 0; i<text.Length; i++) {
		Console.Write(text[i]);
		System.Threading.Thread.Sleep(30);
	}
}
						

The Combat() method takes two Battleship arrays, (one for Cylons and one for vipers) and makes one Cylon rider shoot a viper, and then a viper shoots a Cylon. This is done in turns.


/* *********************************************************
*                       METHOD COMBAT
* *********************************************************/
public int combat(Battleship[,] CylonRaiderSquadron, Battleship[,] vipers) {
	int turn = 0;

	foreach (CylonRaider raider in CylonRaiderSquadron) {
		turn++;
		Console.WriteLine("\n-----------------------");
		Console.WriteLine("\n\tROUND {0}", turn);
		Console.WriteLine("\n-----------------------\n");

		// One raider shoots one of the vipers
		if (raider.Life > 0) {
			raider.Shoot(vipers);
		}

		if (Viper.viperCounter == 0) {
			Console.WriteLine("\n----------------------------------------");
			typeWrite("\n  Cylons win, Human race is wiped out\n\tof the galaxy.\n");
			Console.WriteLine("\n----------------------------------------");
			return 1;
	}//----------------------------------

		foreach (Viper viper in vipers) {
			if (viper.Life > 0) {
				Console.WriteLine("\n" + viper.Pilot + ": " + viper.PilotWarCry);

				// One viper shoots one of the Cylons
				viper.Shoot(CylonRaiderSquadron);
				if (CylonRaider.CylonRaiderCounter == 0) {
					Console.WriteLine("\n----------------------------------------");
					typeWrite("\n  Humans win, Cylons are wiped out... \n  ...for now.\n");
					Console.WriteLine("\n----------------------------------------");
					return 2;
				}//-----------------------------------
			}
		}

		Console.WriteLine("\nThere are {0} Cylons alive!!", CylonRaider.CylonRaiderCounter);
		CylonRaider.printSquadron(CylonRaiderSquadron);

		// Output pseudo control
		if (turn % 5 == 0 && turn % 20 != 0) {
			Console.Write("\nPress enter for 5 more turns ");
			Console.ReadLine();
		}
	}
	return 0;
}
						

And that's all really! Now, if you open this program on your Visual Studio and run it, you will see that you only have to hit Enter for the next round of turns to be displayed on the console.

Try and edit the program so that the player decides which spot in the Cylon's squadron they want to hit, or add any other interaction you come up with!

GitHub BitBucket GitLab

Comments

Have any questions? Spotted any typos? Want to showcase what you did? Found a better solution? Your feedback and suggestions are welcome! And don't forget to share =)