C# Program Organisation

Fundamental C# Program Structures with Examples

This illustrates different structural organization of the same program behaviour, with commentary. The example programs perform the same tasks for circle calculations: asking for a radius, which is input and validated, followed by printing the area and circumference of a circle with that radius. Each version is organised differently, to illustrate the various options available. We start with the simplest organisation, and end with an object-oriented (OO) version, which will only be fully appreciated if you have some OO background.
PREREQUISITES — You should already…
  • have some programming experience, preferably in C/C++/D/Objective-C/Java/Pascal;
  • be conversant with the fundamentals of Object-Oriented Programming (OOP);
  • understand the role of types in a statically typed language;
  • understand expressions, operators and precedence in general.

Flat, C-like Version

The absolute simplest (flat) organization involves having a number of static functions in the same class, which call each other. We use static class… simply because it is the right thing to do, if we want the compiler to check that we comply with our own intentions (have all func­tions as static). Although C# does not have a module keyword, a static class is just about 100% eq­ui­va­lent.

For simpler programs, you can use this program organisation with one file. You can easily add more source files. By convention, each source file contains one static class, giving you a col­lec­tion of modules. From a design perspective, this is equivalent to C-like code, except C does not have proper modules either (it treats source files as an effective module).

Inside such a “module”, you can only have static members, further simplifying the number of rules required to do something useful. Additionally, const creates symbolic constants, which are effectively automatically static.

Another aspect that affects organisation, is that you do not have to define functions before you use them in a file. That means we can write our Main as the first function, even if it calls functions which we define later in the file.

CircApp01.csSimple Circle

Apart from the namespace and the class, and some minor syntax, this is very much the organi­sa­tion of a C program, with some advantages (such as not having to declare functions before using them).

This structure allows you to think in terms of:

Such a program organisation is really only useful for smaller programs, but it is certainly better than having all the code in Main(). You can increase its utility by adding more source files, each with a module (static class). You will then have larger, but still manageable, programs, without re­sort­ing to OOP, as we illustrate in the next section.

Modularised Static Version

There are two variations possible here, but the differences are so small that we won’t show both, only discuss them.

C# files may contain more than one class. We could “modularise” the original code, by placing the circle-related functions in a se­pa­rate, “global” static class (not nested inside the class con­tain­ing Main()). Whether this class is in the same file as the Main() function’s class, or in a se­pa­rate file in the same project, is inconsequential, i.e., it does not affect the syntax, as long as both are in the same namespace. Here is a version split into two files.

CircApp02.csModular Circle

The code for the circle calculations is placed in another class, which in this case, we also a) put in another file, and b) to keep it simple, do not put inside a different namespace.

CircUtils02.csModular Circle

As you can see, the differences compared to the first version, are minor — you simply have to qua­li­fy the calls to the Area() and Circum() functions, by prefixing them with the name of their class. And since it would be redundant to use Circle.CircArea(…), we changed the function names, so it can be written as Circle.Area(…).

Static Class is Equivalent of Module

By making the Circle class static, we ensure that the C# compiler will check that everything inside the class is static, so that we cannot accidentally forget. It is not a requirement, but simply good coding convention in this instance, where it is our intent to only have static func­tions and va­ri­ab­les.

We should also note, before considering the OOP version, that many C# topics can be mastered with only this organisation. You can learn and use all the following topics, without an object-orien­ted design or even deep OOP knowledge:

Of course, you have to at least learn how to use the classes in the .NET Framework, but that is a long way from learning how to efficiently design and write object-oriented code. The more OOP you learn, however, the more you will understand how some of the features that are so easy to use, actually work.

OO Encapsulation Version

Encapsulation is one of the key features of OOP (Object-Oriented Programming). We employ it in this version to encapsulate the concept of a circle as an object — i.e., an abstraction that suits the program’s requirements. We again use a class, but instead of static members, we use in­stan­ce members (methods). As before, whether the class is in the same or another file, makes no dif­fe­ren­ce to the code in Main() using it.

CircApp03.csEncapsulated Circle

The code in Main() is not much more complicated than the previous versions, but now we have a Circle object, which remembers its own radius, and can calculate its own area and cir­cum­fer­ence:

Circle.csEncapsulated Circle

Although such a simple example might not convince you, this promotes re-use and, ultimately, great­er pro­duc­ti­vi­ty. The other advantage is that we can have more than one Circle variable, even arrays of Circle objects, each having their own copies, or instances of the radius_ member. Con­cep­tu­al­ly, they also each have their own copies of the instance methods. This is why many OO texts define an object as “an instance of a class”, and many OOP languages use a syntax like: new SomeClass…, to create a new object from the type SomeClass (remember that a class is a type).

Circle as a Value Type

For such a simple class, we could have implemented it as a struct (value type), instead of a class (reference type), to make it even more like C. But we would not have gained much be­ne­fit from it, other than not having to call new to create a new instance.

Variables of a value type stores all the data comprising the state, while variables of a ref­er­ence type store only the address of (reference to) the data of the object, which must be al­lo­ca­ted with new. It can be called explicitly, or called indirectly by using various short­hand syn­tax variations. For example, these two lines are equivalent; the first one simply uses short­hand syntax:

The System.String (string in C#) is a class, hence a “reference type”, but because it is so common, C# will automatically, in certain circumstances, such as with literal strings, call new.

For a version of Circle using more encapsulation syntax and features, see the separate page for C# Encapsulation Syntax.

Conclusions

The OO encapsulation version is the ideal, but to achieve that, you have to know a) how to en­cap­su­late (easy), b) how to inherit, which requires OOAD (Object-Oriented Analysis & Design), and c) how to implement polymorphism and interfaces, which requires more syntax knowledge, and even more OOAD.

However, and this cannot be stressed enough, there is nothing inherently “wrong” with the other organisations. In particular, the second version already provides numerous benefits, and en­cap­su­la­tion without inheritance and polymorphism, is but a simple step further, with even more pro­mise of reuse. Useful programs do not have to be fully object-oriented.


2017-11-30: Editing. [brx;jjc]
2017-11-26: Additional topics. Editing. [brx;jjc]
2017-08-06: Created. [brx]