UPDATE:
Here's a working implementation based on Mike Nakis' answer regarding lazy initialization:
using System;
public sealed class Room
{
private readonly Func<Room> north;
private readonly Func<Room> south;
private readonly Func<Room> east;
private readonly Func<Room> west;
public Room(
string name,
Func<Room> northExit = null,
Func<Room> southExit = null,
Func<Room> eastExit = null,
Func<Room> westExit = null)
{
this.Name = name;
this.north = northExit ?? new Func<Room>(() => { return null; });
this.south = southExit ?? new Func<Room>(() => { return null; });
this.east = eastExit ?? new Func<Room>(() => { return null; });
this.west = westExit ?? new Func<Room>(() => { return null; });
}
public override string ToString()
{
return this.Name;
}
public string Name { get; }
public Room North
{
get { return this.north(); }
}
public Room South
{
get { return this.south(); }
}
public Room East
{
get { return this.east(); }
}
public Room West
{
get { return this.west(); }
}
public static void Main(string[] args)
{
Room kitchen = null;
Room library = null;
kitchen = new Room
(
name: "Kitchen",
northExit: () => library
);
library = new Room
(
name: "Library",
southExit: () => kitchen
);
Console.WriteLine(
$"The {kitchen} has a northen exit that " +
$"leads to the {kitchen.North}.");
Console.WriteLine(
$"The {library} has a southern exit that " +
$"leads to the {library.South}.");
Console.ReadKey();
}
}