Practice Sorting Custom Classes in C#

Lab Scenario

You are a developer for Northrup Realty, Inc., an organization that specializes in finding commercial and home real estate for buyers in different countries. Your task is to create classes that you and other developers can use to create a .NET Framework application that will allow potential buyers to browse real estate.

To achieve your goals, you will create a base class that represents any type of real estate. Then, you will create custom classes to represent commercial real estate, condominiums, and homes. Next, you will write code to allow a collection of lots to be sorted in different ways. Finally, you will create a user interface for the classes and leverage regular expressions to verify user input.

While the point of this exercise is for you to complete it yourself, you can download the completed solution here: Completed Real Estate Project in C#.

Exercise 1: Create Base Classes

Your manager has asked you to create an extensible, flexible class structure for different types of lots. Initially, you will create classes for commercial lots (that might be used by warehouses, retail stores, or other businesses), condominiums, and private residences. Your structure should be flexible enough to allow you to add other classes in the future, including multi-family homes, farms, and undeveloped land.

The main tasks for this exercise are as follows:

  1. Create a WPF Application in either Visual Basic.NET or C#.
  2. Create a base class call Lot.
  3. From the base Lot class, create a Commercial class.
  4. From the base Lot class, create a Home class.
  5. From the base Home class, create a Condo class.

Task 1: Create a WPF Application in either Visual Basic.NET or C#.

  1. Launch Visual Studio.
  2. Create a new WPF Application project in either Visual C# or Visual Basic. Name the application RealEstate.

Task 2: Create the base Lot class

  1. Add an abstract class to the project named Lot. In C#, use the abstract keyword. In Visual Basic, use the MustInherit keyword. You cannot create an instance of an abstract class. However, you can create classes that inherit from abstract classes. Because we are going to use Lot strictly as a base class, it is a perfect example of when to create an abstract class.
  2. Add the following private properties to the new class:
  • _price (of type Integer)
  • _squareFeet (of type Integer)
  • _acres (of type Double)
  • _streetAddress (of type String)
  • _city (of type String)
  • _state (of type String)
  • _zip (of type String)
  • _listingDate (of type DateTime)
  • _buildDate (of type DateTime)
  1. Add public properties for each of the private properties. In the Get function, return the value from the corresponding private property. In the Set function, write code to validate the value. Use regular expressions to validate the zip code—this will require you to add the System.Text.RegularExpressions namespace. Throw an ArgumentOutOfRangeException exception if the input is invalid.
  2. Override the default ToString method. When ToString is called, return the address and the price of the Lot. You can also return the acreage and square feet.
  3. The C# code should resemble the following:
abstract class Lot
{
    private int _price;
    private int _squareFeet;
    private double _acres;
    private string _streetAddress;
    private string _city;
    private string _state;
    private string _zip;
    private DateTime _listingDate;
    private DateTime _buildDate;

    public int Price
    {
        get
        {
            return _price;
        }

        set
        {
            if (value > 0)
                _price = value;
            else
                throw new ArgumentOutOfRangeException("Price must be a positive value");
        }
    }

    public int SquareFeet
    {
        get
        {
            return _squareFeet;
        }

        set
        {
            if (value > 0)
                _squareFeet = value;
            else
                throw new ArgumentOutOfRangeException("SquareFeet must be a positive value");
        }
    }

    public double Acres
    {
        get
        {
            return _acres;
        }

        set
        {
            if (value > 0)
                _acres = value;
            else
                throw new ArgumentOutOfRangeException("Acres must be a positive value");
        }
    }

    public string StreetAddress
    {
        get
        {
            return _streetAddress;
        }
        set
        {
            if (value.Length > 0)
                _streetAddress = value;
            else
                throw new ArgumentOutOfRangeException("You must provide a value for StreetAddress");
        }
    }

    public string City
    {
        get
        {
            return _city;
        }
        set
        {
            if (value.Length > 0)
                _city = value;
            else
                throw new ArgumentOutOfRangeException("You must provide a value for City");
        }
    }

    public string State
    {
        get
        {
            return _state;
        }
        set
        {
            if (value.Length == 2)
                _state = value;
            else
                throw new ArgumentOutOfRangeException("You must provide a two-character value for State");
        }
    }

    public string Zip
    {
        get
        {
            return _zip;
        }
        set
        {
            if (Regex.IsMatch(value, @"^\d{5}(\-\d{4})?$"))
                _zip = value;
            else
                throw new ArgumentOutOfRangeException("You must provide a valid zip code for Zip");
        }
    }

    public DateTime ListingDate
    {
        get
        {
            return _listingDate;
        }
        set
        {
            if (value.Year > 1900)
                _listingDate = value;
            else
                throw new ArgumentOutOfRangeException("You must provide a valid date, later than the year 1900, for the ListingDate");
        }
    }

    public DateTime BuildDate
    {
        get
        {
            return _buildDate;
        }
        set
        {
            if (value.Year > 0)
                _buildDate = value;
            else
                throw new ArgumentOutOfRangeException("You must provide a valid date, later than the year 0, for the BuildDate");
        }
    }

    public override string ToString()
    {
        return string.Format ("{0}, {1}, {2}: ${3}", StreetAddress, City, State, Price);
    }
}

Task 3: Create the Commercial class

  1. Add a class to the project named Commercial.
  2. Derive the class from Lot.
  3. Create an Enumeration type named CommercialLotType, with options for ShoppingCenter, Restaurant, Office, Storage, and Parking.
  4. Add the following public lots to the new class:
  • SignVisible (of type Boolean)
  • Type (of type CommercialLotType)
  1. Create a constructor that accepts parameters for every Lot defined by both Commercial and the base Lot class.

The C# code should resemble the following:

class Commercial : Lot
{
    public enum CommercialLotType
    {
        ShoppingCenter,
        Restaurant,
        Office,
        Storage,
        Parking
    }

    public bool SignVisible;
    public CommercialLotType Type;

    public Commercial(int _price, int _squareFeet, double _acres, string _streetAddress, string _city, string _state, string _zip, DateTime _listingDate, DateTime _buildDate, CommercialLotType _type, bool _signVisible)
    {
        this.Price = _price;
        this.SquareFeet = _squareFeet;
        this.Acres = _acres;
        this.StreetAddress = _streetAddress;
        this.City = _city;
        this.State = _state;
        this.Zip = _zip;
        this.ListingDate = _listingDate;
        this.BuildDate = _buildDate;
        this.Type = _type;
        this.SignVisible = _signVisible;
    }
}

Task 4: Create the Home class

  1. Add a class to the project named Home.
  2. Derive the class from Lot.
  3. Create an Enumeration type named HomeLotType, with options for SingleFamily, MultiFamily, Mobile.
  4. Add the following public lots to the new class:
  • Bedrooms (of type Int)
  • Bathrooms (of type Int)
  • Type (of type HomeLotType)
  1. Create a constructor that accepts parameters for every property defined by both Home and the base Lot class.
  2. Create a constructor that accepts zero parameters. This will be required when you derive the Condo class from the Home class.

The C# code should resemble the following:

class Home : Lot
{
    public enum HomeLotType
    {
        SingleFamily,
        MultiFamily,
        Mobile
    }

    public int Bedrooms;
    public int Bathrooms;
    public HomeLotType Type;

    public Home(int _price, int _squareFeet, double _acres, string _streetAddress, string _city, string _state, string _zip, DateTime _listingDate, DateTime _buildDate, int _bedrooms, int _bathrooms, HomeLotType _type)
    {
        this.Price = _price;
        this.SquareFeet = _squareFeet;
        this.Acres = _acres;
        this.StreetAddress = _streetAddress;
        this.City = _city;
        this.State = _state;
        this.Zip = _zip;
        this.ListingDate = _listingDate;
        this.BuildDate = _buildDate;
        this.Type = _type;
        this.Bedrooms = _bedrooms;
        this.Bathrooms = _bathrooms;
    }

    public Home()
    {
    }
}

Task 5: Create the Condo class

  1. Add a class to the project named Condo.
  2. Derive the class from Home.
  3. Add the following public lots to the new class:
  • Gym (of type Boolean)
  • Pool (of type Boolean)
  • MonthlyFees (of type Double)
  1. Create a constructor that accepts parameters for every property defined by Condo, the base Home class, and the base Lot class. Do not define the Home.Type class, however.

The C# code should resemble the following:

class Condo : Home
{
    public bool Gym;
    public bool Pool;
    public double MonthlyFees;

    public Condo(int _price, int _squareFeet, double _acres, string _streetAddress, string _city, string _state, string _zip, DateTime _listingDate, DateTime _buildDate, int _bedrooms, int _bathrooms, bool _gym, bool _pool, double _monthlyFees)
    {
        this.Price = _price;
        this.SquareFeet = _squareFeet;
        this.Acres = _acres;
        this.StreetAddress = _streetAddress;
        this.City = _city;
        this.State = _state;
        this.Zip = _zip;
        this.ListingDate = _listingDate;
        this.BuildDate = _buildDate;
        this.Bedrooms = _bedrooms;
        this.Bathrooms = _bathrooms;

        this.Gym = _gym;
        this.Pool = _pool;
        this.MonthlyFees = _monthlyFees;
    }
}

Exercise 2: Enable Sorting

Task 1: Implement a default sorter in Lot

  1. In the Lot class, implement the generic IComparable interface using the Lot type.
  2. Override the CompareTo method, and compare based on the Lot.Price property.
  3. The CompareTo method should resemble the following:
public int  CompareTo(Lot l1)
{
    return this.Price.CompareTo(l1.Price);
}

Task 2: Create a class named LotComparer, based on IComparer, that can sort by Price, SquareFeet, Acres, or City.

  1. Create a new class named LotComparer.
  2. Implement the generic IComparer interface.
  3. Create an enumeration named ComparisonType with values for Price, SquareFeet, Acres, and City.
  4. Create an instance of ComparisonType named ComparisonMethod.
  5. Override the Compare method to call the proper underlying CompareTo method. For example, if ComparisonMethod is set to SquareFeet, you should call the SquareFeet.CompareTo method. A switch command works well for this.

The new class should resemble the following in C#:

class LotComparer : IComparer<Lot>
{
    public enum ComparisonType
    { Price, SquareFeet, Acres, City }

    public ComparisonType ComparisonMethod;

    public int Compare(Lot p1, Lot p2)
    {
        switch (ComparisonMethod)
        {
            case LotComparer.ComparisonType.SquareFeet:
                return p1.SquareFeet.CompareTo(p2.SquareFeet);
            case LotComparer.ComparisonType.Acres:
                return p1.Acres.CompareTo(p2.Acres);
            case LotComparer.ComparisonType.City:
                return p1.City.CompareTo(p2.City);
            default:
                return p1.Price.CompareTo(p2.Price);
        }
    }
}

Exercise 3: Create the User Interface

Task 1: Design the XAML user interface

  1. Add a ComboBox named SortComboBox. Optionally, add a label beside the ComboBox that reads Sort by:.
  2. Add a ListBox named LotListBox.

The user interface should resemble the following:

Task 2: Populate the LotListBox

  1. Create a Window.Loaded event handler. The XAML Window declaration should now resemble the following:
<Window x:Class="RealEstate.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Real Estate" Height="199" Width="312"
    Loaded="Window_Loaded">
</Window>
  1. Within the Window1 class, add a Lot array named lots. Create 5 elements for the array.
  2. In the Window.Loaded event handler, create five instances of Commercial, Home, and Condo, and add them to the lots array. This should resemble:
lots[0] = new Commercial(500000, 10000, 1.5, "100 Cardinal Rd", "Anytown", "MA", "01331", DateTime.Now, new DateTime(2009, 9, 1), Commercial.CommercialLotType.Office, true);
lots[1] = new Home(250000, 2500, .5, "12 Bluejay St", "Mytown", "CT", "02492", DateTime.Now, new DateTime(1955, 5, 1), 2, 1, Home.HomeLotType.SingleFamily);
lots[2] = new Condo(150000, 1000, .1, "10 Crow Ave", "Yourtown", "VT", "12020", DateTime.Now, new DateTime(1963, 8, 3), 1, 1, true, true, 200);
lots[3] = new Commercial(750000, 12000, 5, "77 Eagle Cir", "Histown", "NH", "02439", DateTime.Now, new DateTime(2004, 3, 15), Commercial.CommercialLotType.Restaurant, true);
lots[4] = new Home(450000, 4500, 5.5, "12 Heron Blvd", "Hertown", "NY", "02394", DateTime.Now, new DateTime(1988, 7, 1), 5, 3, Home.HomeLotType.SingleFamily);
  1. Set the LotListBox.ItemsSource value to the lots array. The Window1 class should now resemble the following in C#:
public partial class Window1 : Window
{

    Lot[] lots = new Lot[5];

    public Window1()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        lots[0] = new Commercial(500000, 10000, 1.5, "100 Cardinal Rd", "Anytown", "MA", "01331", DateTime.Now, new DateTime(2009, 9, 1), Commercial.CommercialLotType.Office, true);
        lots[1] = new Home(250000, 2500, .5, "12 Bluejay St", "Mytown", "CT", "02492", DateTime.Now, new DateTime(1955, 5, 1), 2, 1, Home.HomeLotType.SingleFamily);
        lots[2] = new Condo(150000, 1000, .1, "10 Crow Ave", "Yourtown", "VT", "12020", DateTime.Now, new DateTime(1963, 8, 3), 1, 1, true, true, 200);
        lots[3] = new Commercial(750000, 12000, 5, "77 Eagle Cir", "Histown", "NH", "02439", DateTime.Now, new DateTime(2004, 3, 15), Commercial.CommercialLotType.Restaurant, true);
        lots[4] = new Home(450000, 4500, 5.5, "12 Heron Blvd", "Hertown", "NY", "02394", DateTime.Now, new DateTime(1988, 7, 1), 5, 3, Home.HomeLotType.SingleFamily);

        LotListBox.ItemsSource = lots;
}

Task 3: Populate the SortComboBox

  1. In the Window.Loaded event handler, set the SortComboBox.ItemsSource value to the LotComparer.ComparisonType enumeration. You can do that using the following code:
SortComboBox.ItemsSource = Enum.GetValues(typeof(LotComparer.ComparisonType));
  1. After you populate the SortComboBox, select the first item by setting SortComboBox.SelectedIndex to 0.
  1. Add the SortComboBox.SelectionChanged event handler to the XAML. The XAML for the SortComboBox should resemble the following:
<ComboBox Height="23" Margin="104,8,8,0" Name="SortComboBox" VerticalAlignment="Top" SelectionChanged="SortComboBox_SelectionChanged" />
  1. Implement the SortComboBox.SelectionChanged event handler so that the lots array is re-sorted by the selected item, and the LotListBox is refreshed. You can do that with the following code:
private void SortComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    LotComparer pc = new LotComparer();
    pc.ComparisonMethod = (LotComparer.ComparisonType)SortComboBox.SelectedItem;
    Array.Sort<Lot>(lots, pc);

    LotListBox.Items.Refresh();
}

Task 4: Test the application

  1. Run the application. Select different items in the SortComboBox and notice that the lots are re-sorted. The Window1 class should now resemble the following in C#:
public partial class Window1 : Window
{

    Lot[] lots = new Lot[5];

    public Window1()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        lots[0] = new Commercial(500000, 10000, 1.5, "100 Cardinal Rd", "Anytown", "MA", "01331", DateTime.Now, new DateTime(2009, 9, 1), Commercial.CommercialLotType.Office, true);
        lots[1] = new Home(250000, 2500, .5, "12 Bluejay St", "Mytown", "CT", "02492", DateTime.Now, new DateTime(1955, 5, 1), 2, 1, Home.HomeLotType.SingleFamily);
        lots[2] = new Condo(150000, 1000, .1, "10 Crow Ave", "Yourtown", "VT", "12020", DateTime.Now, new DateTime(1963, 8, 3), 1, 1, true, true, 200);
        lots[3] = new Commercial(750000, 12000, 5, "77 Eagle Cir", "Histown", "NH", "02439", DateTime.Now, new DateTime(2004, 3, 15), Commercial.CommercialLotType.Restaurant, true);
        lots[4] = new Home(450000, 4500, 5.5, "12 Heron Blvd", "Hertown", "NY", "02394", DateTime.Now, new DateTime(1988, 7, 1), 5, 3, Home.HomeLotType.SingleFamily);

        LotListBox.ItemsSource = lots;

        SortComboBox.ItemsSource = Enum.GetValues(typeof(LotComparer.ComparisonType));
        SortComboBox.SelectedIndex = 0;

    }

    private void SortComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        LotComparer pc = new LotComparer();
        pc.ComparisonMethod = (LotComparer.ComparisonType)SortComboBox.SelectedItem;
        Array.Sort<Lot>(lots, pc);

        LotListBox.Items.Refresh();
    }
}

Lab Resources

While the point of this exercise is for you to complete it yourself, you can download the completed solution here: Completed Real Estate Project in C#.

Return to the .NET Framework Fundamentals Tutorials Table of Contents.

public partial class Window1 : Window

{

Lot[] lots = new Lot[5];

public Window1()

{

InitializeComponent();

}

private void Window_Loaded(object sender, RoutedEventArgs e)

{

lots[0] = new Commercial(500000, 10000, 1.5, “100 Cardinal Rd”, “Anytown”, “MA”, “01331″, DateTime.Now, new DateTime(2009, 9, 1), Commercial.CommercialLotType.Office, true);

lots[1] = new Home(250000, 2500, .5, “12 Bluejay St”, “Mytown”, “CT”, “02492″, DateTime.Now, new DateTime(1955, 5, 1), 2, 1, Home.HomeLotType.SingleFamily);

lots[2] = new Condo(150000, 1000, .1, “10 Crow Ave”, “Yourtown”, “VT”, “12020″, DateTime.Now, new DateTime(1963, 8, 3), 1, 1, true, true, 200);

lots[3] = new Commercial(750000, 12000, 5, “77 Eagle Cir”, “Histown”, “NH”, “02439″, DateTime.Now, new DateTime(2004, 3, 15), Commercial.CommercialLotType.Restaurant, true);

lots[4] = new Home(450000, 4500, 5.5, “12 Heron Blvd”, “Hertown”, “NY”, “02394″, DateTime.Now, new DateTime(1988, 7, 1), 5, 3, Home.HomeLotType.SingleFamily);

LotListBox.ItemsSource = lots;

}

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>