Website development and design blog, tutorials and inspiration

Introducing C# Classes and Structs

What are classes

By , 6th November 2007 in C#

In this tutorial we will cover the basic concepts of classes; this is an important topic so it will be split into several tutorials to ensure that you understand them.

Classes are a fundamental aspect of object orientated programming, and the topic is a very broad subject which will be covered in these tutorials.

Classes encompass the whole concept of Object Orientated Programming, which can be a confusing subject and difficult to get your head around. If you are not familiar with the concept of Object Orientation, we recommend that you read our Object Orientated Primer first, which discusses the topic as a concept rather than this tutorial which uses a programmatical approach.

We are going to stop using Hello World from now on and instead focus or more real life examples in order to teach classes and object orientated programming.

A C# application is a collection of classes, structures and types.

Firstly, classes and structs are essentially the same, apart from two differences. Classes are a reference type, structs are value types and classes can use inheritance whereas structs cannot. We will cover reference and value types in the next tutorial, and inheritance in a later tutorial.

Microsoft defines a class as "a set of data combined with methods (or functions) that can manipulate that data".

Defining a Class

A class is introduced using the class keyword, followed by the name of the class you are creating. Because a class is a block of code, it requires the use of curly brackets (braces).

Let's use the example in the Object Orientated Primer and create a Car class. I've called the class baseCarClass because we will be using this class as a base for new classes in future tutorials.

  1. class baseCarClass
  2. {
  3. }

In the primer, we identified several fields and methods associated with a car class. We are going to create a baseCarClass, so create a new console project, create a new class and have a go at adding these field and methods to it. You will need to decide what data type would be best suited to that particular field. For any methods, please fill out a dummy method with no parameters and no return type.

Here is one of the values that we identified in the primer:

  • is engine running - Field

Here are a few more that we are going to use in these tutorials. You will need to decide if the item should be a field or a method, and the data type.

  • start engine
  • accelerate
  • brake
  • speed
  • stop engine
  • distance travelled
  • fuel level
  • colour

The compiler is not affected by the order in which you declare fields or methods; however, it greatly improves readability if you declare fields and properties at the start of a class, followed by its methods.

  1. class baseCarClass
  2. {
  3. public bool isEngineRunning;
  4. public decimal speed;
  5. public decimal distanceTraveled;
  6. public decimal fuelLevel;
  7. public Color colour;
  9. public void startEngine()
  10. {
  11. }
  13. void accelerate()
  14. {
  15. }
  17. void brake()
  18. {
  19. }
  21. void stopEngine()
  22. {
  23. }
  24. }

You will notice in this code that I have used a new keyword here, "public" before I declare a variable. This will be covered in more depth when we talk about Access Modifiers and Scope, but for now, public means that any method or class can access this value. You may also notice that I haven't used the static keyword, as I have done previously. This is because static means that the method or property can be accessed without creating an instance of the baseCarClass which we don't want to do, after all, you can't have a car colour without a car can you?

Because we have not used the static keyword when defining the class, we must create an instance of it in order to use it. This is done using the "new" keyword.

In your Main method, create an instance of the baseCarClass:

  1. static void Main()
  2. {
  3. baseCarClass myCar = new baseCarClass();
  4. }

A class is a user-defined type so we use the same syntax as declaring an int (for example), but a class also needs initialising with the new keyword. This will instantiate an instance of the class on the heap.

Full listing

  1. using System;
  3. class TestBaseCarClass
  4. {
  5. static void Main()
  6. {
  7. baseCarClass myCar = new baseCarClass();
  8. }
  9. }
  11. class baseCarClass
  12. {
  13. public bool isEngineRunning;
  14. public decimal speed;
  15. public decimal distanceTraveled;
  16. public decimal fuelLevel;
  17. public Color colour;
  19. public void startEngine()
  20. {
  21. }
  23. void accelerate()
  24. {
  25. }
  27. void brake()
  28. {
  29. }
  31. void stopEngine()
  32. {
  33. }
  34. }

IntelliSense demo

On the line after we create an instance of baseCarClass, type in myCar followed by a full stop. Notice how IntelliSense will pop-up and show us the methods and fields of our class, as well as a few other properties (Equals, GetHashCode, GetType and ToString).

IntelliSense demonstration
IntelliSense demonstration


Structs are very similar to classes, in fact from a syntax and declaration point of view they are the same. The main difference is that classes are reference types while structs are value types.

For a class, this means that you are working with a reference to a memory location, so when you pass a class into a function, you are actually passing in a memory location. The function then works with the same class values in the same memory area.

A struct, on the other hand, is a value type, which means that you are working with the values directly. When you pass a struct into a function you are passing a copy of the values.

We can see this in action in this short test program. It will hopefully make things a little clearer.

  1. using System;
  3. class TestClass
  4. {
  5. public string testString;
  6. }
  8. struct TestStruct
  9. {
  10. public string testString;
  11. }
  13. class StructVsClass
  14. {
  15. static void Main()
  16. {
  17. // Create an instance of each type
  18. TestClass instanceOfClass = new TestClass();
  19. TestStruct instanceOfStruct = new TestStruct();
  21. // Initialise testString parameter
  22. instanceOfClass.testString = "This is a test";
  23. instanceOfStruct.testString = "This is a test";
  25. // Call method to change test on each type
  26. ChangeTestClass(instanceOfClass);
  27. ChangeTestStruct(instanceOfStruct);
  29. // Output results
  30. Console.WriteLine("Class: " + instanceOfClass.testString);
  31. Console.WriteLine("Struct: " + instanceOfStruct.testString);
  32. }
  34. public static void ChangeTestClass(TestClass test)
  35. {
  36. test.testString = "Changed Text from ChangeTestClass()";
  37. }
  39. public static void ChangeTestStruct(TestStruct test)
  40. {
  41. test.testString = "Changed Text from TestStruct()";
  42. }
  43. }

Starting off, we have a TestClass and a TestStruct, which as you can see are the same. In the Main method, we create an instance of each and set the value of both to "This is a test", then call a method to change the value of the text. In each case, we pass in the class or the struct and set the text to "Changed Text from Change...Class()". Finally, output the text value to the console.

What would you expect the results to show?

Class: Changed Text from ChangeTestClass()
Struct: This is a test
Press any key to continue . . .

So from this, we can see that the class has had its value changed, but the struct hasn't. Why is this?

Well, we passed the class to the function as a reference type, meaning that we actually passed a memory location. The method used this memory location to change the text, so when the original class accessed the data again it's looking at the same location and therefore the new text.

When we passed in the struct, we passed a copy of the data to the method, which then changed the copy. The original struct and its data were unaffected.


There are no comments for this post. Be the first!

Leave a Reply

Your email address will not be published.