HomeSearch

C# class Examples (Nested Class)

Instantiate a class with a constructor. Examine fields and methods on classes.
Class. Far in the distance a castle stands. Fog settles in the area. This castle guards the nearby town—its deep moat protects from invaders.
Class keyword. A class in C# guards its information. Like the castle it keeps its treasure away from outsiders. Classes are everywhere in this language.KeywordsStruct
Class example. This program defines a class named Box, with one public method Open(). This class is a type, a template, that does nothing.

Main: The program begins in Main. Here the Box is created with "new" and Open() is called, printing a message with Console.WriteLine.

Console
C# program that uses class class Box { public void Open() { System.Console.WriteLine("Box opened"); } } class Program { static void Main() { // The program begins here. // ... Create a new Box and call Open on it. Box box = new Box(); box.Open(); } } Output Box opened
Nested class. Here we see a nested class instance. Nested classes refer to class declarations that occur in other class declarations.

Class B: This class is enclosed inside the declaration of class A. Class B is thus a nested class.

Public: Because it has a public accessibility modifier, class B can be accessed in places other than class A's scope.

Here: We create an instance of A and an instance of A.B. The instance of A does not contain an instance of B.

C# program that shows nested class class A { public int _v1; public class B { public int _v2; } } class Program { static void Main() { A a = new A(); a._v1++; A.B ab = new A.B(); ab._v2++; } }
Field ordering. In a class, does the ordering of fields matter? In older languages, sometimes it does—bytes must be next to each other to fit into 4-byte words.Optimization

Here: I test how effectively the C# compiler "packs" fields. I measure memory usage of classes. I break down all the allocations.

Info: In class "A", the byte and int fields are not grouped by their type. But in class "B", the bytes and ints are grouped by type.

Main: The Main method allocates 100,000 instances of both classes. The array memory usage is measured.

C# program that tests class field ordering using System; class A { byte b1; int i1; byte b2; int i2; byte b3; int i3; byte b4; int i4; } class B { byte b1; byte b2; byte b3; byte b4; int i1; int i2; int i3; int i4; } class Program { static void Main() { // ... Measure class "A". long m1 = GC.GetTotalMemory(true); A[] ar1 = new A[100000]; for (int i = 0; i < ar1.Length; i++) { ar1[i] = new A(); } long m2 = GC.GetTotalMemory(true); Console.WriteLine(m2 - m1); Console.WriteLine((m2 - m1) / 100000); ar1[0] = null; ar1 = null; // ... Measure class "B". long m3 = GC.GetTotalMemory(true); B[] ar2 = new B[100000]; for (int i = 0; i < ar2.Length; i++) { ar2[i] = new B(); } long m4 = GC.GetTotalMemory(true); Console.WriteLine(m4 - m3); Console.WriteLine((m4 - m3) / 100000); ar2[0] = null; ar2 = null; } } Output 3200016 [bytes total, A] 32 [bytes per element, A] 3200016 [bytes total, B] 32 [bytes per element, B]
Field, results. Ordering did not matter for memory usage. So you can place your fields in any order you like in the source code file—it makes no difference.

Objects: The class reference (within the arrays) accounted for 4 bytes per object. An empty class (with no fields) required 12 bytes.

However: A class with just one int field also required 12 bytes. This is the smallest class size possible.

Info: I included the 4 bytes from the first int into the minimum class size. Then I added all the remaining fields.

And: The four byte fields occupied only four bytes. They were effectively packed together in memory.

Memory usage: Class reference: 4 bytes Class, empty: 12 bytes Class with 1 int: 12 bytes Int: 4 bytes 4 bytes 4 bytes 4 bytes Byte: 1 byte 1 byte 1 byte 1 byte Total: 4 bytes (reference) 12 bytes (class with 1 int) 12 bytes (3 remaining ints) 4 bytes (fields) = 32 bytes
Constructor. We often need to have different ways of instantiating a class. We might use the class in many places. With overloading, we can add many entry points for creating the class.Constructor
This, base. In class bodies, we use the "this" keyword before a field, method or property identifier. It is an instance expression. We use "base" to indicate a parent instance.ThisBase
Generics. A generic class is compiled for a certain parameter type, one specified in angle brackets. Generics (like Dictionary) are powerful. They are often faster than alternatives.Generics
Namespaces are an organizational feature. Often, programs will have namespaces containing their classes. This changes the syntax. It alters how we must identify a target class.Namespace
Object. Every class is derived from the ultimate base class—object. Because of this, every variable can be cast to an object reference. We treat any variable as one type.Object
Static. The word "static" refers to a position that is unchanging, fixed. A static class cannot be instantiated. Its position in memory is therefore fixed in one place.Static
Inheritance is a key feature of the class model. We use inheritance to simplify a program—to make it easier to add new features. We explore inheritance, type derivation and polymorphism.Inheritance
Private, public. Classes are by default private. Programmers are less likely to misuse private classes. When we make a class public, we can instantiate it in external locations.Public, privateProtected, internal
Properties. These are an important feature. They give us a way to add executable code in a syntax form that resembles a simple memory access. They have uses in data-binding.Property
Indexer. An indexer is a type of property. It is used with simple syntax—the same syntax used for array accesses. This is a form of syntactic sugar.Indexer
Readonly. This modifier is used to denote a field that can be initialized, but not changed later in program execution. A readonly field is initialized at runtime.Readonly
Variable initializer. We can assign fields directly in their class declarations. The C# compiler automatically moves the initialization to the constructor.Variable Initializer
Operators. For some types, it make sense to overload operators. An overloaded operator can make syntax simpler. We can add classes together. We can use unary or binary operators.Operator
Partial. A partial class is contained in more than one file. This is a feature used often by Visual Studio in Windows Forms. It is not that important.partial
Sealed. This keyword is used to specify that a class cannot be derived from. It has performance benefits, but it is not critical to understanding the language.Sealed
Abstract. An abstract class cannot be directly instantiated. It is used, in derivation, to create other classes. Unlike abstract art, we may eventually understand this.Abstract
Attribute. This is attached to a type such as a class. It becomes part of the metadata. It is used to influence the compiler's behavior on the type. Types are changed with no runtime cost.Attribute
A summary. With classes, we create instances of custom types. This gives a great power to model data. With models, we tame the dragon of complexity (a formidable beast).
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.
Home
Dot Net Perls