Chapter 8

 

Nested Classes

 

Nested classes are classes created within existing classes.

 

a.cs

public class zzz

{

class yyy

{

}

public static void Main()

{

}

}

 

A simple example is shown above where class yyy is created within class zzz.

 

a.cs

public class zzz

{

public static void Main()

{

xxx x = new xxx();

}

}

class yyy

{

class xxx

{

}

}

 

Compiler Error

a.cs(5,1): error CS0246: The type or namespace name 'xxx' could not be found (are you missing a using directive or an assembly reference?)

 

We are not allowed to use the class xxx directly as it exists inside yyy and has no permanent existence at all by itself. We cannot even define an object that looks like xxx.

 

a.cs

public class zzz

{

public static void Main()

{

yyy.xxx a = new yyy.xxx();

}

}

public class yyy

{

public xxx abc()

{

return new xxx();

}

public class xxx

{

}

}

 

The actual name of class xxx is yyy.xxx as it is nested within the class yyy.

 

a.cs

public class zzz

{

public static void Main()

{

yyy.xxx a = new yyy.xxx();

System.Console.WriteLine(a.i);

}

}

public class yyy

{

public xxx abc()

{

return new xxx();

}

public class xxx

{

public static int i = 10;

}

}

 

Compiler Error

a.cs(7,26): error CS0176: Static member 'yyy.xxx.i' cannot be accessed with an instance reference; use typename instead

 

The member i is static, hence we need the name of the class and not name of object.

 

a.cs

public class zzz {

public static void Main() {

yyy.xxx a = new yyy.xxx();

System.Console.WriteLine(yyy.xxx.i);

}

}

public class yyy

{

public xxx abc()

{

return new xxx();

}

public class xxx

{

public static int i = 10;

}

}

Output

10

 

Static members work the same way everywhere. No instance name required, only the name of class or classes.

 

a.cs

public class zzz

{

public static void Main()

{

yyy.xxx a = new yyy.xxx();

System.Console.WriteLine(a.j);

}

}

public class yyy

{

public int j = 2;

public xxx abc()

{

return new xxx();

}

public class xxx

{

public int i = 100;

}

}

 

Compiler Error

a.cs(7,26): error CS0117: 'yyy.xxx' does not contain a definition for 'j'

 

The member j is in the class yyy, not in xxx and hence the above error.

 

a.cs

public class zzz

{

public static void Main()

{

yyy.xxx a = new yyy.xxx();

System.Console.WriteLine(a.pqr());

}

}

public class yyy

{

public int j = 2;

public xxx abc()

{

return new xxx();

}

public class xxx

{

public int i = 100;

public int pqr()

{

return j;

}

}

}

 

Compiler Error

a.cs(22,8): error CS0038: Cannot access a non-static member of outer type 'yyy' via nested type 'yyy.xxx'

 

The nested class xxx cannot access the member j in class yyy as it is non-static. The fields of the containing class are not automatically available to the nested class.

 

a.cs

public class zzz

{

public static void Main()

{

yyy.xxx a = new yyy.xxx();

System.Console.WriteLine(a.pqr());

}

}

public class yyy

{

public static int j = 2;

public xxx abc()

{

return new xxx();

}

public class xxx

{

public int i = 100;

public int pqr()

{

return yyy.j;

}

}

}

 

Output

2

 

The nested class xxx can access static members of the class by simply doing what everyone else does, that is preface the member with the name of the class.

 

a.cs

public class zzz {

public static void Main() {

yyy.xxx a = new yyy.xxx();

System.Console.WriteLine(a.pqr());

}

}

public class yyy

{

public int j = 2;

public xxx abc()

{

return new xxx();

}

public class xxx

{

public int i = 100;

public int pqr()

{

yyy h = new yyy();

return h.j;

}

}

}

Output

2

 

The non-static members can be accessed as normal but we have to create an object that looks like yyy.

 

a.cs

public class zzz

{

public static void Main()

{

yyy a = new yyy();

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy");

}

public class xxx

{

public xxx()

{

System.Console.WriteLine("xxx");

}

}

}

 

Output

yyy

 

Creating an object that looks like yyy does not create one that looks like the nested class xxx as the constructor of class xxx does not get called at all.

 

a.cs

public class zzz {

public static void Main()

{

yyy.abc();

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy");

}

public static void abc()

{

xxx x = new xxx();

}

public class xxx

{

public xxx()

{

System.Console.WriteLine("xxx");

}

}

}

 

Output

xxx

 

The nested class is independent of the containing class it resides in. The static function abc creates an object that looks like xxx but the constructor of the class yyy  is not executed.

 

a.cs

class zzz {

public class yyy

{

public static int v = 9;

}

}

class xxx : zzz

{

public static void Main()

{

zzz a = new zzz();

System.Console.WriteLine(a.yyy.v);

}

}

Compiler Error

a.cs(12,28): error CS0572: 'yyy': cannot reference a type through an expression; try 'zzz.yyy' instead

 

The compiler comes back with the right answer. As the member v is static, we have no choice but to use the name of the class zzz and then the name of the inner class.

 

a.cs

class zzz

{

public class yyy

{

public static int v;

}

}

class xxx : zzz

{

public static void Main()

{

xxx.yyy.v = 5;

}

}

 

The compiler gives no error messages. We are allowed to access a static member as shown in the program above.

 

a.cs

class zzz

{

static void abc(int i)

{

}

static void abc(string s)

{

}

class yyy

{

void pqr()

{

abc(1);                                     

abc("Hello");

}

static void abc(long l)

{

}

}

}

 

Compiler Error

a.cs(14,1): error CS1502: The best overloaded method match for 'zzz.yyy.abc(long)' has some invalid arguments

a.cs(14,5): error CS1503: Argument '1': cannot convert from 'string' to 'long'

 

The class zzz has two static functions abc that accepts an int and a string. The nested class yyy creates one more abc that accepts a long. The problem in this is that the two abc's in class yyy get hidden. The compiler can convert a number one into a long, but cannot convert the string into a long. Remove the abc from class yyy to see the error disappear.

 

a.cs

class zzz {

class yyy : zzz {

public static void Main() {

}

}

}

 

The above example does not give us a circular reference as the class yyy is derived from class zzz and it is also a nested class within zzz. A circular reference occurs only if the class zzz in turn is derived from class yyy directly or indirectly. Remember no one likes circular references. A class is not dependent upon the classes it nests in.

 

a.cs

public class zzz {

private static int i4 = 0;

public class yyy

{

public static int i1= 2;

internal static int i2 = 1;

private static int i3 = 0;

}

public class xxx

{

public static void Main()

{

zzz.yyy.i1= 1;

zzz.yyy.i2= 2;

zzz.yyy.i3= 3;

}

}

}

 

Compiler Error

a.cs(15,1): error CS0122: 'zzz.yyy.i3' is inaccessible due to its protection level

 

The same rules binding access modifiers apply to nested classes. The field i1 can be used everywhere. The field i2 being internal can be used only in the current project and finally i3 being private as i4 is used only in class yyy and the containing class zzz.

 

a.cs

public class zzz

{

private static int i4 = 0;

private class yyy

{

public static int i1= 2;

internal static int i2 = 1;

private static int i3 = 0;

}

public class xxx

{

public static void Main()

{

zzz.yyy.i1= 1;

zzz.yyy.i2= 2;

zzz.yyy.i3= 3;

}

}

}

Compiler Error

a.cs(16,1): error CS0122: 'zzz.yyy.i3' is inaccessible due to its protection level

 

Same explanation as above. Only difference the nested class yyy is now private and not public but nothing changes.

 

a.cs

namespace mmm

{

public class zzz

{

private class xxx

{

public static int i1 = 0;

internal static int i2 = 0;

private static int i3 = 0;

}

}

public class yyy

{

public static void Main()

{

zzz.xxx.i1= 1;   // zzz

zzz.xxx.i2= 2; // zzz

zzz.xxx.i3= 3;  // xxx

}

}

}

 

Compiler Error

a.cs(16,1): error CS0122: 'mmm.zzz.xxx' is inaccessible due to its protection level

a.cs(17,1): error CS0122: 'mmm.zzz.xxx' is inaccessible due to its protection level

a.cs(18,1): error CS0122: 'mmm.zzz.xxx' is inaccessible due to its protection level

 

We have placed everything in a namespace. Now i1 and i2 and i3 are not accessible in class yyy. i1 and i2 are accessible in class zzz and i3 only in class xxx. The explanation has been given earlier.