Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Daniel Solis - Illustrated C# 2010 - 2010.pdf
Скачиваний:
16
Добавлен:
11.06.2015
Размер:
11.23 Mб
Скачать

CHAPTER 25 OTHER TOPICS

Nested Types

Types are usually declared directly inside a namespace. You can, however, also declare types inside a class or struct declaration.

Types declared inside another type declaration are called nested types. Like all type declarations, nested types are templates for an instance of the type.

A nested type is declared like a member of the enclosing type.

A nested type can be any type.

An enclosing type can be either a class or a struct.

For example, the following code shows class MyClass, with a nested class called MyCounter.

class MyClass

// Enclosing class

{

 

class MyCounter

// Nested class

{

 

...

 

}

 

...

 

}

 

Declaring a type as a nested type often makes sense if it’s only meant to be used as a helper for the enclosing type.

Don’t be confused by the term nested. Nested refers to the location of the declaration—not the location of any instances. Although a nested type’s declaration is inside the enclosing type’s declaration, objects of the nested type are not necessarily enclosed in objects of the enclosing type. Objects of the nested type—if any are created at all—are located wherever they would have been located had they not been declared inside another type.

For example, Figure 25-6 shows objects of types MyClass and MyCounter, as outlined in the preceding code. The figure additionally shows a field called Counter, in class MyClass, that is a reference to an object of the nested class, which is located elsewhere in the heap.

Figure 25-6. Nesting refers to the location of the declaration, not the location of the object.

684

CHAPTER 25 OTHER TOPICS

Example of a Nested Class

The following code fleshes out classes MyClass and MyCounter into a full program. MyCounter implements an integer counter that starts at 0 and can be incremented using the ++ operator. When the constructor for MyClass is called, it creates an instance of the nested class and assigns the reference to the field. Figure 25-7 illustrates the structure of the objects in the code.

class MyClass

 

{

 

class MyCounter

// Nested class

{

 

private int _Count = 0;

 

public int Count

// Read-only property

{

 

get { return _Count; }

 

}

 

public static MyCounter operator++( MyCounter current )

{

current._Count++; return current;

}

}

 

 

private MyCounter counter;

// Field of nested class

public MyClass() { counter = new MyCounter(); }

// Constructor

public int Incr()

{ return (counter++).Count; }

// Increment method

public int GetValue() { return counter.Count; }

// Get counter value

}

 

 

class Program

 

 

{

 

 

static void Main( )

 

 

{

 

 

MyClass mc = new MyClass();

// Create object

mc.Incr(); mc.Incr(); mc.Incr();

// Increment it.

mc.Incr(); mc.Incr(); mc.Incr();

// Increment it.

Console.WriteLine("Total: {0}", mc.GetValue());

// Print its value.

}

 

 

}

 

 

685

CHAPTER 25 OTHER TOPICS

This code produces the following output:

Total: 6

Figure 25-7. Objects of a nested class and its enclosing class

Visibility and Nested Types

In Chapter 7, you learned that classes, and types in general, can have an access level of either public or internal. Nested types, however, are different in that they have member accessibility rather than type accessibility. Therefore, the following are true:

A nested type declared inside a class can have any of the five class member accessibility levels public, protected, private, internal, or protected internal.

A nested type declared inside a struct can have one of the three struct member accessibility levels public, internal, or private.

In both cases, the default access level of a nested type is private, which means it cannot be seen outside the enclosing type.

The relationship between the members of the enclosing class and the nested class is a little less straightforward and is illustrated in Figure 25-8. The nested type has complete access to the members of the enclosing type, regardless of their declared accessibility, including members that are private and protected.

The relationship, however, is not symmetrical. Although the members of the enclosing type can always see the nested type declaration and create variables and instances of it, they do not have complete access to its members. Instead, their access is limited to the declared access of the nested class members—just as if the nested type were a separate type. That is, they can access the public and internal members but cannot access the private or protected members of the nested type.

686

CHAPTER 25 OTHER TOPICS

Figure 25-8. Accessibility between nested type members and enclosing type members

You can summarize this relationship as follows:

The members of a nested type always have full access rights to members of the enclosing type.

The members of an enclosing type

Always have access to the nested type itself

Only have the declared access rights to members of the nested type

The visibility of nested types can also affect the inheritance of base members. If the enclosing class is a derived class, a nested type can hide a base class member with the same name. Use the new modifier with the declaration of the nested class to make the hiding explicit.

A this reference within a nested type refers to the object of the nested type—not the object of the enclosing type. If an object of the nested type needs access to the enclosing type, it must have a reference to it. You can have the enclosing object supply its this reference as a parameter to the nested type’s constructor, as shown in the following code:

687

CHAPTER 25 OTHER TOPICS

class SomeClass

// Enclosing class

{

 

 

 

int Field1 = 15, Field2 = 20;

// Fields of enclosing class

MyNested mn = null;

// Reference to nested class

public void PrintMyMembers()

 

 

{

mn.PrintOuterMembers();

// Call method in nested class

}

 

 

 

public SomeClass()

// Constructor

 

{

mn = new MyNested(this);

// Create instance of nested class

 

}

 

 

 

Pass in the reference to the enclosing class.

 

class MyNested

// Nested class declaration

{

SomeClass sc = null;

// Reference to enclosing class

 

 

public MyNested(SomeClass SC)

// Constructor of the nested class

 

{

 

 

 

sc = SC;

// Store reference to enclosing class

 

}

 

 

 

public void PrintOuterMembers()

 

 

 

{

 

 

 

Console.WriteLine("Field1: {0}", sc.Field1);

// Enclosing field

 

Console.WriteLine("Field2: {0}", sc.Field2);

// Enclosing field

}

}

// End of nested class

 

}

 

 

 

class Program {

static void Main( ) {

SomeClass MySC = new SomeClass(); MySC.PrintMyMembers();

}

}

This code produces the following output:

Field1: 15

Field2: 20

688

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]