The other answers have addressed why the compiler doesn't complain about
c.a.a.a.
...
I'd like to address why the ability to write self-referential classes is useful. There are many situations (kinds of data) in the world that have hierarchical data that looks similar from different levels. People at different levels of a management hierarchy come to mind:
public class Employee
{
public Employee Supervisor { get; set; }
public IEnumerable<employee> Subordinates { get; private set; }
}
Another common example is location. I currently work for a health-care organization. We have a location table that has:
Beds, that are in
Rooms, that are in
Units, that are in
Buildings, that are in
Facilities (i.e. hospitals).
(One could imagine this list extending to Neighborhood, City, County, State, Country, for some national health-care database).
All of these items are considered locations, so could be (and are commonly) implemented by means of a common class.
Using a loop, instead of the
c.a.a.a.
... syntax, to 'chain' a bunch of identical (nested) class references, might look like this:
public enum LocationType { Bed, Room, Unit, Building, Facility }
public class Location
{
public LocationType LocationType { get; set; }
public Location ContainingLocation { get; set; }
public IEnumerable<location> ContainedLocations { get; private set; }
public Location GetContainingFacility()
{
Location parent = this.ContainingLocation;
while (parent != null && parent.LocationType != LocationType.Facility)
parent = parent.ContainingLocation;
return parent;
}
}
If this method were called on a
Location
that had
LocationType == LocationType.Bed
, then the
GetContainingFacility()
method above would return the same as:
Location aBed = new Location();
Location facility = aBed
.ContainingLocation
.ContainingLocation
.ContainingLocation
.ContainingLocation;
Naturally, whether you use
c.a.a.a.
...,
aBed.ContainingLocation.
..., or a loop, things can get confusing when a type contains a reference to another instance of that type. What really helps in this situation is to use field, property and method names that are as descriptive as possible (such as
ContainingLocation
).