Class
C# is an object-oriented language, and it uses classes extensively. The class
keyword specifies a type that can be instantiated, and the term "object" refers to class
instances.
To continue, a key benefit of classes is that a class
hides its information from other parts of a program. Unlike a struct
, a class
is always located on the heap region of memory.
Class
exampleThis program defines a class
named Box, with one public method Open()
. This class
is a type, a template, that does nothing.
Main
. Here the Box is created with "new" and Open()
is called, printing a message with Console.WriteLine
.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(); } }Box opened
class
Here we see a nested class
instance. Nested classes refer to class
declarations that occur in other class
declarations.
Class
B is enclosed inside the declaration of class
A. It is thus a nested class
.class
B can be accessed in places other than class
A's scope.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++; } }
The C# language supports inheritance—we can inherit from regular classes, and from abstract
classes. Here we have a Vehicle base class
, and Car derives from Vehicle.
override
method on the Car class
is called.using System; class Vehicle { public virtual void Test() { Console.WriteLine("Vehicle Test"); } } class Car : Vehicle { public override void Test() { Console.WriteLine("Car Test"); } } class Program { static void Main() { // Use the derived class and call its override Test method. Vehicle c = new Car(); c.Test(); } }Car Test
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.
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
method allocates 100,000 instances of both classes. The array memory usage is measured.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; } }3200016 [bytes total, A] 32 [bytes per element, A] 3200016 [bytes total, B] 32 [bytes per element, B]
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.
class
reference (within the arrays) accounted for 4 bytes per object. An empty class
(with no fields) required 12 bytes.class
with just one int
field also required 12 bytes. This is the smallest class
size possible.int
into the minimum class size. Then I added all the remaining fields.byte
fields occupied only four bytes. They were effectively packed together in memory.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
With classes, we create instances of custom types. This gives a great power to model data. C# is a language based around classes, and they help keep it usable.