House plan design (Head First C#)












5












$begingroup$


I've been working through the book Head First C# and this is an exercise from chapter 7, which is about interfaces and abstract classes.



Note that the class design was mandated by the authors, I'm open to suggestions to improve.



I'd like a review on any and all aspects. My code ended up quite a bit different than the book's solution, because it's a few years old and I think "holds back" on newer C#/.NET features and syntax.



In a shared code base, I would include that XML documentation, but since this is just local code for learning, I didn't. Any and all feedback appreciated.





The authors' published implementation is here on GitHub. The idea is to implement a floor plan that can be explored, with room connections and doors to the outside. It's done through a WinForms application.



Here is a picture of the plan from the book. Sorry, couldn't find a screenshot.



floorplan



The app looks like this:



app





Location.cs



using System;

namespace House
{
abstract class Location
{
public Location(string name) => Name = name;

public string Name { get; private set; }
public Location Exits;

public virtual string Description
{
get
{
string description = $"You're standing in the {Name}. You see exits to the following places: rn";
foreach (Location exit in Exits)
{
description += $"— {exit.Name}";
if (exit != Exits[Exits.Length - 1])
{
description += "rn";
}
}
return description;
}
}
}
}


Room.cs



using System;

namespace House
{
class Room : Location
{
public Room(string name, string decoration)
: base(name)
{
Decoration = decoration;
}

private string Decoration { get; set; }

public override string Description => $"You see {Decoration}. {base.Description} ";
}
}


Outside.cs



using System;

namespace House
{
class Outside : Location
{
public Outside(string name, bool hot)
: base(name)
{
Hot = hot;
}

private bool Hot { get; }

override public string Description => Hot
? "It's very hot here. " + base.Description
: base.Description;
}
}




IHasInteriorDoor.cs



using System;

namespace House
{
interface IHasExteriorDoor
{
string DoorDescription { get; }
Location DoorLocation { get; }
}
}




OutsideWithDoor.cs



using System;

namespace House
{
class OutsideWithDoor : Outside, IHasExteriorDoor
{
public OutsideWithDoor(string name, bool hot, string doorDescription)
: base(name, hot)
{
DoorDescription = doorDescription;
}

public string DoorDescription { get; private set; }

public Location DoorLocation { get; set; }

public override string Description => $"{base.Description}rn You see {DoorDescription} to go inside.";
}
}


RoomWithDoor.cs



using System;

namespace House
{
class RoomWithDoor : Room, IHasExteriorDoor
{
public RoomWithDoor(string name, string decoration, string doorDescription)
: base(name, decoration)
{
DoorDescription = doorDescription;
}

public string DoorDescription { get; private set; }

public Location DoorLocation { get; set; }
}
}




And here is the WinForms to make it work. Leaving out IDE generated code.



ExploreTheHouseForm.cs



using System;
using System.Windows.Forms;

namespace House
{
public partial class ExploreTheHouseForm : Form
{
Location currentLocation;

RoomWithDoor livingRoom;
RoomWithDoor kitchen;
Room diningRoom;
OutsideWithDoor frontYard;
OutsideWithDoor backYard;
Outside garden;

public ExploreTheHouseForm()
{
InitializeComponent();
CreateObjects();
MoveToLocation(livingRoom);
}

private void CreateObjects()
{
// Configure the locations
livingRoom = new RoomWithDoor("living room", "an antique carpet", "an oak door with a brass knob");
kitchen = new RoomWithDoor("kitchen", "stainless steel appliances", "a screen door");
diningRoom = new Room("dining room", "a crystal chandelier");
frontYard = new OutsideWithDoor("front yard", false, livingRoom.DoorDescription);
backYard = new OutsideWithDoor("back yard", true, kitchen.DoorDescription);
garden = new Outside("garden", false);

// Configure the exits
livingRoom.Exits = new Location { diningRoom };
kitchen.Exits = new Location { diningRoom };
diningRoom.Exits = new Location { livingRoom, kitchen };
frontYard.Exits = new Location { backYard, garden };
backYard.Exits = new Location { frontYard, garden };
garden.Exits = new Location { frontYard, backYard };

// Configure exterior doors
livingRoom.DoorLocation = frontYard;
frontYard.DoorLocation = livingRoom;
kitchen.DoorLocation = backYard;
backYard.DoorLocation = kitchen;
}

private void MoveToLocation(Location location)
{
currentLocation = location;
ExitsComboBox.Items.Clear();
foreach (Location exit in location.Exits)
{
ExitsComboBox.Items.Add(exit.Name);
}
ExitsComboBox.SelectedIndex = 0;
DescriptionTextBox.Text = currentLocation.Description;
ShowGoThroughExteriorDoorButton(currentLocation);
}

private void ShowGoThroughExteriorDoorButton(Location location)
{
if (location is IHasExteriorDoor)
{
GoThroughExteriorDoorButton.Visible = true;
return;
}
GoThroughExteriorDoorButton.Visible = false;
}

private void GoHereButton_Click(object sender, EventArgs e)
{
MoveToLocation(currentLocation.Exits[ExitsComboBox.SelectedIndex]);
}

private void GoThroughExteriorDoorButton_Click(object sender, EventArgs e)
{
IHasExteriorDoor locationWithExteriorDoor = currentLocation as IHasExteriorDoor;
MoveToLocation(locationWithExteriorDoor.DoorLocation);
}
}
}









share|improve this question











$endgroup$

















    5












    $begingroup$


    I've been working through the book Head First C# and this is an exercise from chapter 7, which is about interfaces and abstract classes.



    Note that the class design was mandated by the authors, I'm open to suggestions to improve.



    I'd like a review on any and all aspects. My code ended up quite a bit different than the book's solution, because it's a few years old and I think "holds back" on newer C#/.NET features and syntax.



    In a shared code base, I would include that XML documentation, but since this is just local code for learning, I didn't. Any and all feedback appreciated.





    The authors' published implementation is here on GitHub. The idea is to implement a floor plan that can be explored, with room connections and doors to the outside. It's done through a WinForms application.



    Here is a picture of the plan from the book. Sorry, couldn't find a screenshot.



    floorplan



    The app looks like this:



    app





    Location.cs



    using System;

    namespace House
    {
    abstract class Location
    {
    public Location(string name) => Name = name;

    public string Name { get; private set; }
    public Location Exits;

    public virtual string Description
    {
    get
    {
    string description = $"You're standing in the {Name}. You see exits to the following places: rn";
    foreach (Location exit in Exits)
    {
    description += $"— {exit.Name}";
    if (exit != Exits[Exits.Length - 1])
    {
    description += "rn";
    }
    }
    return description;
    }
    }
    }
    }


    Room.cs



    using System;

    namespace House
    {
    class Room : Location
    {
    public Room(string name, string decoration)
    : base(name)
    {
    Decoration = decoration;
    }

    private string Decoration { get; set; }

    public override string Description => $"You see {Decoration}. {base.Description} ";
    }
    }


    Outside.cs



    using System;

    namespace House
    {
    class Outside : Location
    {
    public Outside(string name, bool hot)
    : base(name)
    {
    Hot = hot;
    }

    private bool Hot { get; }

    override public string Description => Hot
    ? "It's very hot here. " + base.Description
    : base.Description;
    }
    }




    IHasInteriorDoor.cs



    using System;

    namespace House
    {
    interface IHasExteriorDoor
    {
    string DoorDescription { get; }
    Location DoorLocation { get; }
    }
    }




    OutsideWithDoor.cs



    using System;

    namespace House
    {
    class OutsideWithDoor : Outside, IHasExteriorDoor
    {
    public OutsideWithDoor(string name, bool hot, string doorDescription)
    : base(name, hot)
    {
    DoorDescription = doorDescription;
    }

    public string DoorDescription { get; private set; }

    public Location DoorLocation { get; set; }

    public override string Description => $"{base.Description}rn You see {DoorDescription} to go inside.";
    }
    }


    RoomWithDoor.cs



    using System;

    namespace House
    {
    class RoomWithDoor : Room, IHasExteriorDoor
    {
    public RoomWithDoor(string name, string decoration, string doorDescription)
    : base(name, decoration)
    {
    DoorDescription = doorDescription;
    }

    public string DoorDescription { get; private set; }

    public Location DoorLocation { get; set; }
    }
    }




    And here is the WinForms to make it work. Leaving out IDE generated code.



    ExploreTheHouseForm.cs



    using System;
    using System.Windows.Forms;

    namespace House
    {
    public partial class ExploreTheHouseForm : Form
    {
    Location currentLocation;

    RoomWithDoor livingRoom;
    RoomWithDoor kitchen;
    Room diningRoom;
    OutsideWithDoor frontYard;
    OutsideWithDoor backYard;
    Outside garden;

    public ExploreTheHouseForm()
    {
    InitializeComponent();
    CreateObjects();
    MoveToLocation(livingRoom);
    }

    private void CreateObjects()
    {
    // Configure the locations
    livingRoom = new RoomWithDoor("living room", "an antique carpet", "an oak door with a brass knob");
    kitchen = new RoomWithDoor("kitchen", "stainless steel appliances", "a screen door");
    diningRoom = new Room("dining room", "a crystal chandelier");
    frontYard = new OutsideWithDoor("front yard", false, livingRoom.DoorDescription);
    backYard = new OutsideWithDoor("back yard", true, kitchen.DoorDescription);
    garden = new Outside("garden", false);

    // Configure the exits
    livingRoom.Exits = new Location { diningRoom };
    kitchen.Exits = new Location { diningRoom };
    diningRoom.Exits = new Location { livingRoom, kitchen };
    frontYard.Exits = new Location { backYard, garden };
    backYard.Exits = new Location { frontYard, garden };
    garden.Exits = new Location { frontYard, backYard };

    // Configure exterior doors
    livingRoom.DoorLocation = frontYard;
    frontYard.DoorLocation = livingRoom;
    kitchen.DoorLocation = backYard;
    backYard.DoorLocation = kitchen;
    }

    private void MoveToLocation(Location location)
    {
    currentLocation = location;
    ExitsComboBox.Items.Clear();
    foreach (Location exit in location.Exits)
    {
    ExitsComboBox.Items.Add(exit.Name);
    }
    ExitsComboBox.SelectedIndex = 0;
    DescriptionTextBox.Text = currentLocation.Description;
    ShowGoThroughExteriorDoorButton(currentLocation);
    }

    private void ShowGoThroughExteriorDoorButton(Location location)
    {
    if (location is IHasExteriorDoor)
    {
    GoThroughExteriorDoorButton.Visible = true;
    return;
    }
    GoThroughExteriorDoorButton.Visible = false;
    }

    private void GoHereButton_Click(object sender, EventArgs e)
    {
    MoveToLocation(currentLocation.Exits[ExitsComboBox.SelectedIndex]);
    }

    private void GoThroughExteriorDoorButton_Click(object sender, EventArgs e)
    {
    IHasExteriorDoor locationWithExteriorDoor = currentLocation as IHasExteriorDoor;
    MoveToLocation(locationWithExteriorDoor.DoorLocation);
    }
    }
    }









    share|improve this question











    $endgroup$















      5












      5








      5





      $begingroup$


      I've been working through the book Head First C# and this is an exercise from chapter 7, which is about interfaces and abstract classes.



      Note that the class design was mandated by the authors, I'm open to suggestions to improve.



      I'd like a review on any and all aspects. My code ended up quite a bit different than the book's solution, because it's a few years old and I think "holds back" on newer C#/.NET features and syntax.



      In a shared code base, I would include that XML documentation, but since this is just local code for learning, I didn't. Any and all feedback appreciated.





      The authors' published implementation is here on GitHub. The idea is to implement a floor plan that can be explored, with room connections and doors to the outside. It's done through a WinForms application.



      Here is a picture of the plan from the book. Sorry, couldn't find a screenshot.



      floorplan



      The app looks like this:



      app





      Location.cs



      using System;

      namespace House
      {
      abstract class Location
      {
      public Location(string name) => Name = name;

      public string Name { get; private set; }
      public Location Exits;

      public virtual string Description
      {
      get
      {
      string description = $"You're standing in the {Name}. You see exits to the following places: rn";
      foreach (Location exit in Exits)
      {
      description += $"— {exit.Name}";
      if (exit != Exits[Exits.Length - 1])
      {
      description += "rn";
      }
      }
      return description;
      }
      }
      }
      }


      Room.cs



      using System;

      namespace House
      {
      class Room : Location
      {
      public Room(string name, string decoration)
      : base(name)
      {
      Decoration = decoration;
      }

      private string Decoration { get; set; }

      public override string Description => $"You see {Decoration}. {base.Description} ";
      }
      }


      Outside.cs



      using System;

      namespace House
      {
      class Outside : Location
      {
      public Outside(string name, bool hot)
      : base(name)
      {
      Hot = hot;
      }

      private bool Hot { get; }

      override public string Description => Hot
      ? "It's very hot here. " + base.Description
      : base.Description;
      }
      }




      IHasInteriorDoor.cs



      using System;

      namespace House
      {
      interface IHasExteriorDoor
      {
      string DoorDescription { get; }
      Location DoorLocation { get; }
      }
      }




      OutsideWithDoor.cs



      using System;

      namespace House
      {
      class OutsideWithDoor : Outside, IHasExteriorDoor
      {
      public OutsideWithDoor(string name, bool hot, string doorDescription)
      : base(name, hot)
      {
      DoorDescription = doorDescription;
      }

      public string DoorDescription { get; private set; }

      public Location DoorLocation { get; set; }

      public override string Description => $"{base.Description}rn You see {DoorDescription} to go inside.";
      }
      }


      RoomWithDoor.cs



      using System;

      namespace House
      {
      class RoomWithDoor : Room, IHasExteriorDoor
      {
      public RoomWithDoor(string name, string decoration, string doorDescription)
      : base(name, decoration)
      {
      DoorDescription = doorDescription;
      }

      public string DoorDescription { get; private set; }

      public Location DoorLocation { get; set; }
      }
      }




      And here is the WinForms to make it work. Leaving out IDE generated code.



      ExploreTheHouseForm.cs



      using System;
      using System.Windows.Forms;

      namespace House
      {
      public partial class ExploreTheHouseForm : Form
      {
      Location currentLocation;

      RoomWithDoor livingRoom;
      RoomWithDoor kitchen;
      Room diningRoom;
      OutsideWithDoor frontYard;
      OutsideWithDoor backYard;
      Outside garden;

      public ExploreTheHouseForm()
      {
      InitializeComponent();
      CreateObjects();
      MoveToLocation(livingRoom);
      }

      private void CreateObjects()
      {
      // Configure the locations
      livingRoom = new RoomWithDoor("living room", "an antique carpet", "an oak door with a brass knob");
      kitchen = new RoomWithDoor("kitchen", "stainless steel appliances", "a screen door");
      diningRoom = new Room("dining room", "a crystal chandelier");
      frontYard = new OutsideWithDoor("front yard", false, livingRoom.DoorDescription);
      backYard = new OutsideWithDoor("back yard", true, kitchen.DoorDescription);
      garden = new Outside("garden", false);

      // Configure the exits
      livingRoom.Exits = new Location { diningRoom };
      kitchen.Exits = new Location { diningRoom };
      diningRoom.Exits = new Location { livingRoom, kitchen };
      frontYard.Exits = new Location { backYard, garden };
      backYard.Exits = new Location { frontYard, garden };
      garden.Exits = new Location { frontYard, backYard };

      // Configure exterior doors
      livingRoom.DoorLocation = frontYard;
      frontYard.DoorLocation = livingRoom;
      kitchen.DoorLocation = backYard;
      backYard.DoorLocation = kitchen;
      }

      private void MoveToLocation(Location location)
      {
      currentLocation = location;
      ExitsComboBox.Items.Clear();
      foreach (Location exit in location.Exits)
      {
      ExitsComboBox.Items.Add(exit.Name);
      }
      ExitsComboBox.SelectedIndex = 0;
      DescriptionTextBox.Text = currentLocation.Description;
      ShowGoThroughExteriorDoorButton(currentLocation);
      }

      private void ShowGoThroughExteriorDoorButton(Location location)
      {
      if (location is IHasExteriorDoor)
      {
      GoThroughExteriorDoorButton.Visible = true;
      return;
      }
      GoThroughExteriorDoorButton.Visible = false;
      }

      private void GoHereButton_Click(object sender, EventArgs e)
      {
      MoveToLocation(currentLocation.Exits[ExitsComboBox.SelectedIndex]);
      }

      private void GoThroughExteriorDoorButton_Click(object sender, EventArgs e)
      {
      IHasExteriorDoor locationWithExteriorDoor = currentLocation as IHasExteriorDoor;
      MoveToLocation(locationWithExteriorDoor.DoorLocation);
      }
      }
      }









      share|improve this question











      $endgroup$




      I've been working through the book Head First C# and this is an exercise from chapter 7, which is about interfaces and abstract classes.



      Note that the class design was mandated by the authors, I'm open to suggestions to improve.



      I'd like a review on any and all aspects. My code ended up quite a bit different than the book's solution, because it's a few years old and I think "holds back" on newer C#/.NET features and syntax.



      In a shared code base, I would include that XML documentation, but since this is just local code for learning, I didn't. Any and all feedback appreciated.





      The authors' published implementation is here on GitHub. The idea is to implement a floor plan that can be explored, with room connections and doors to the outside. It's done through a WinForms application.



      Here is a picture of the plan from the book. Sorry, couldn't find a screenshot.



      floorplan



      The app looks like this:



      app





      Location.cs



      using System;

      namespace House
      {
      abstract class Location
      {
      public Location(string name) => Name = name;

      public string Name { get; private set; }
      public Location Exits;

      public virtual string Description
      {
      get
      {
      string description = $"You're standing in the {Name}. You see exits to the following places: rn";
      foreach (Location exit in Exits)
      {
      description += $"— {exit.Name}";
      if (exit != Exits[Exits.Length - 1])
      {
      description += "rn";
      }
      }
      return description;
      }
      }
      }
      }


      Room.cs



      using System;

      namespace House
      {
      class Room : Location
      {
      public Room(string name, string decoration)
      : base(name)
      {
      Decoration = decoration;
      }

      private string Decoration { get; set; }

      public override string Description => $"You see {Decoration}. {base.Description} ";
      }
      }


      Outside.cs



      using System;

      namespace House
      {
      class Outside : Location
      {
      public Outside(string name, bool hot)
      : base(name)
      {
      Hot = hot;
      }

      private bool Hot { get; }

      override public string Description => Hot
      ? "It's very hot here. " + base.Description
      : base.Description;
      }
      }




      IHasInteriorDoor.cs



      using System;

      namespace House
      {
      interface IHasExteriorDoor
      {
      string DoorDescription { get; }
      Location DoorLocation { get; }
      }
      }




      OutsideWithDoor.cs



      using System;

      namespace House
      {
      class OutsideWithDoor : Outside, IHasExteriorDoor
      {
      public OutsideWithDoor(string name, bool hot, string doorDescription)
      : base(name, hot)
      {
      DoorDescription = doorDescription;
      }

      public string DoorDescription { get; private set; }

      public Location DoorLocation { get; set; }

      public override string Description => $"{base.Description}rn You see {DoorDescription} to go inside.";
      }
      }


      RoomWithDoor.cs



      using System;

      namespace House
      {
      class RoomWithDoor : Room, IHasExteriorDoor
      {
      public RoomWithDoor(string name, string decoration, string doorDescription)
      : base(name, decoration)
      {
      DoorDescription = doorDescription;
      }

      public string DoorDescription { get; private set; }

      public Location DoorLocation { get; set; }
      }
      }




      And here is the WinForms to make it work. Leaving out IDE generated code.



      ExploreTheHouseForm.cs



      using System;
      using System.Windows.Forms;

      namespace House
      {
      public partial class ExploreTheHouseForm : Form
      {
      Location currentLocation;

      RoomWithDoor livingRoom;
      RoomWithDoor kitchen;
      Room diningRoom;
      OutsideWithDoor frontYard;
      OutsideWithDoor backYard;
      Outside garden;

      public ExploreTheHouseForm()
      {
      InitializeComponent();
      CreateObjects();
      MoveToLocation(livingRoom);
      }

      private void CreateObjects()
      {
      // Configure the locations
      livingRoom = new RoomWithDoor("living room", "an antique carpet", "an oak door with a brass knob");
      kitchen = new RoomWithDoor("kitchen", "stainless steel appliances", "a screen door");
      diningRoom = new Room("dining room", "a crystal chandelier");
      frontYard = new OutsideWithDoor("front yard", false, livingRoom.DoorDescription);
      backYard = new OutsideWithDoor("back yard", true, kitchen.DoorDescription);
      garden = new Outside("garden", false);

      // Configure the exits
      livingRoom.Exits = new Location { diningRoom };
      kitchen.Exits = new Location { diningRoom };
      diningRoom.Exits = new Location { livingRoom, kitchen };
      frontYard.Exits = new Location { backYard, garden };
      backYard.Exits = new Location { frontYard, garden };
      garden.Exits = new Location { frontYard, backYard };

      // Configure exterior doors
      livingRoom.DoorLocation = frontYard;
      frontYard.DoorLocation = livingRoom;
      kitchen.DoorLocation = backYard;
      backYard.DoorLocation = kitchen;
      }

      private void MoveToLocation(Location location)
      {
      currentLocation = location;
      ExitsComboBox.Items.Clear();
      foreach (Location exit in location.Exits)
      {
      ExitsComboBox.Items.Add(exit.Name);
      }
      ExitsComboBox.SelectedIndex = 0;
      DescriptionTextBox.Text = currentLocation.Description;
      ShowGoThroughExteriorDoorButton(currentLocation);
      }

      private void ShowGoThroughExteriorDoorButton(Location location)
      {
      if (location is IHasExteriorDoor)
      {
      GoThroughExteriorDoorButton.Visible = true;
      return;
      }
      GoThroughExteriorDoorButton.Visible = false;
      }

      private void GoHereButton_Click(object sender, EventArgs e)
      {
      MoveToLocation(currentLocation.Exits[ExitsComboBox.SelectedIndex]);
      }

      private void GoThroughExteriorDoorButton_Click(object sender, EventArgs e)
      {
      IHasExteriorDoor locationWithExteriorDoor = currentLocation as IHasExteriorDoor;
      MoveToLocation(locationWithExteriorDoor.DoorLocation);
      }
      }
      }






      c# winforms interface xaml






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 3 hours ago







      Phrancis

















      asked 4 hours ago









      PhrancisPhrancis

      14.7k646139




      14.7k646139






















          1 Answer
          1






          active

          oldest

          votes


















          5












          $begingroup$

          I have a general rule: if I see string concatenation with a loop I assume it's not the best way of doing it. Let's look at this:



          foreach (Location exit in Exits)
          {
          description += $"— {exit.Name}";
          if (exit != Exits[Exits.Length - 1])
          {
          description += "rn";
          }
          }


          I see this pattern a lot. What you need is Select with string.Join:



          var exitList = string.Join(Environment.NewLine, Exits.Select(exit => $"— {exit.Name}"));


          I've used Environment.NewLine because I like using well-named constants. Random aside: r is a Carriage Return and n is a Line Feed. The terminology comes from physical printers. Another reason I prefer Environment.NewLine is that it means you don't have to know and remember that.





          The Name property of Location is only set in the constructor. You can use a read-only auto property instead of a private set one:



          public string Name { get; }




          Outside.Description could be using string interpolation like the other Description properties.





          You're missing your access modifiers on your class declarations. MS guidelines state that they should always be specified.





          I'm not aware of a convention for it but override public string seems to be an odd order to me. I would expect the access modifier first: public override string. The main thing is to keep that consistent though.






          share|improve this answer









          $endgroup$













            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211662%2fhouse-plan-design-head-first-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            5












            $begingroup$

            I have a general rule: if I see string concatenation with a loop I assume it's not the best way of doing it. Let's look at this:



            foreach (Location exit in Exits)
            {
            description += $"— {exit.Name}";
            if (exit != Exits[Exits.Length - 1])
            {
            description += "rn";
            }
            }


            I see this pattern a lot. What you need is Select with string.Join:



            var exitList = string.Join(Environment.NewLine, Exits.Select(exit => $"— {exit.Name}"));


            I've used Environment.NewLine because I like using well-named constants. Random aside: r is a Carriage Return and n is a Line Feed. The terminology comes from physical printers. Another reason I prefer Environment.NewLine is that it means you don't have to know and remember that.





            The Name property of Location is only set in the constructor. You can use a read-only auto property instead of a private set one:



            public string Name { get; }




            Outside.Description could be using string interpolation like the other Description properties.





            You're missing your access modifiers on your class declarations. MS guidelines state that they should always be specified.





            I'm not aware of a convention for it but override public string seems to be an odd order to me. I would expect the access modifier first: public override string. The main thing is to keep that consistent though.






            share|improve this answer









            $endgroup$


















              5












              $begingroup$

              I have a general rule: if I see string concatenation with a loop I assume it's not the best way of doing it. Let's look at this:



              foreach (Location exit in Exits)
              {
              description += $"— {exit.Name}";
              if (exit != Exits[Exits.Length - 1])
              {
              description += "rn";
              }
              }


              I see this pattern a lot. What you need is Select with string.Join:



              var exitList = string.Join(Environment.NewLine, Exits.Select(exit => $"— {exit.Name}"));


              I've used Environment.NewLine because I like using well-named constants. Random aside: r is a Carriage Return and n is a Line Feed. The terminology comes from physical printers. Another reason I prefer Environment.NewLine is that it means you don't have to know and remember that.





              The Name property of Location is only set in the constructor. You can use a read-only auto property instead of a private set one:



              public string Name { get; }




              Outside.Description could be using string interpolation like the other Description properties.





              You're missing your access modifiers on your class declarations. MS guidelines state that they should always be specified.





              I'm not aware of a convention for it but override public string seems to be an odd order to me. I would expect the access modifier first: public override string. The main thing is to keep that consistent though.






              share|improve this answer









              $endgroup$
















                5












                5








                5





                $begingroup$

                I have a general rule: if I see string concatenation with a loop I assume it's not the best way of doing it. Let's look at this:



                foreach (Location exit in Exits)
                {
                description += $"— {exit.Name}";
                if (exit != Exits[Exits.Length - 1])
                {
                description += "rn";
                }
                }


                I see this pattern a lot. What you need is Select with string.Join:



                var exitList = string.Join(Environment.NewLine, Exits.Select(exit => $"— {exit.Name}"));


                I've used Environment.NewLine because I like using well-named constants. Random aside: r is a Carriage Return and n is a Line Feed. The terminology comes from physical printers. Another reason I prefer Environment.NewLine is that it means you don't have to know and remember that.





                The Name property of Location is only set in the constructor. You can use a read-only auto property instead of a private set one:



                public string Name { get; }




                Outside.Description could be using string interpolation like the other Description properties.





                You're missing your access modifiers on your class declarations. MS guidelines state that they should always be specified.





                I'm not aware of a convention for it but override public string seems to be an odd order to me. I would expect the access modifier first: public override string. The main thing is to keep that consistent though.






                share|improve this answer









                $endgroup$



                I have a general rule: if I see string concatenation with a loop I assume it's not the best way of doing it. Let's look at this:



                foreach (Location exit in Exits)
                {
                description += $"— {exit.Name}";
                if (exit != Exits[Exits.Length - 1])
                {
                description += "rn";
                }
                }


                I see this pattern a lot. What you need is Select with string.Join:



                var exitList = string.Join(Environment.NewLine, Exits.Select(exit => $"— {exit.Name}"));


                I've used Environment.NewLine because I like using well-named constants. Random aside: r is a Carriage Return and n is a Line Feed. The terminology comes from physical printers. Another reason I prefer Environment.NewLine is that it means you don't have to know and remember that.





                The Name property of Location is only set in the constructor. You can use a read-only auto property instead of a private set one:



                public string Name { get; }




                Outside.Description could be using string interpolation like the other Description properties.





                You're missing your access modifiers on your class declarations. MS guidelines state that they should always be specified.





                I'm not aware of a convention for it but override public string seems to be an odd order to me. I would expect the access modifier first: public override string. The main thing is to keep that consistent though.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered 48 mins ago









                RobHRobH

                14.4k42661




                14.4k42661






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211662%2fhouse-plan-design-head-first-c%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Polycentropodidae

                    Magento 2 Error message: Invalid state change requested

                    Paulmy