Question

In an inventory program, I have made classes Item and ItemCollection, as well as a derived class Computer : Item.

In a form, I create an ItemCollection (a generic list of Items) called TheseItems (including some Computers) and I want to display the properties of each item ThisItem (like location, quantity, etc.).

While doing this, I want to also display distinct properties for computers (such as CPU, HDD, and RAM). I have this so far:

foreach (Item ThisItem in TheseItems)
{
    //Display properties of Item instance “ThisItem” (Excluded for ease of reading)

    if (ThisItem is Computer)
    {
        //Display distinct properties of Computer instance “ThisItem”
    }
}

So far, there are no errors, but I’m not sure how to proceed. Is it possible to do what I want?

EDIT: Thanks, steak! I was worried that casting wouldn't allow me to access pre-assigned properties (and merely allow the to assign new ones), but I was fortunately mistaken! I now have:

Computer ThisComputer = ThisItem as Computer;
if (Computer != null)
{
     //Display distinct properties of Computer instance “ThisComputer”
}

I'm really impressed with the quick help I received. Thanks!

Was it helpful?

Solution

What you have will work.

foreach (Item ThisItem in TheseItems)
{
    //Display properties of Item instance “ThisItem” (Excluded for ease of reading)

    if (ThisItem is Computer)
    {
        Computer computerItem = (Computer)ThisItem;
        //Display distinct properties of Computer instance “ThisItem”
    }
}

Or use the as keyword for a slight optimization:

foreach (Item ThisItem in TheseItems)
{
    //Display properties of Item instance “ThisItem” (Excluded for ease of reading)
    var computerItem = ThisItem as Computer;
    if (computerItem != null)
    {
        //Display distinct properties of Computer instance “ThisItem”
    }
}

Also, a friend of mine wrote a nice utility class to helps with this. I thought I'd post it since it's turned out to be very useful.

foreach (Item ThisItem in TheseItems)
{
    //Display properties of Item instance “ThisItem” (Excluded for ease of reading)
    ThisItem.Match()
            .Case<Computer>(comp => /* Do stuff with your computer */)
            .Case<Television>(tv => /* Do stuff with your television */)
            .Default(item => /* Do stuff with your item */);
}

The utility class looks something like this. Below gives the gist, and it's very expandable.

public class Matcher<TMatch>
{
    private readonly TMatch _matchObj;
    private bool _isMatched;

    public Matcher(TMatch matchObj)
    {
        this._matchObj = matchObj;
    }

    public Matcher<TMatch> Case<TCase>(Action<TCase> action) where TCase : TMatch
    {
        if(this._matchObj is TCase)
        {
            this.DoCase(() => action((TCase)this._matchObj));
        }
        return this;
    }

    public void Default(Action<TMatch> action)
    {
        this.DoCase(() => action(this._matchObj));
    }

    private void DoCase(Action action)
    {
        if (!this._isMatched)
        {
            action();
            this._isMatched = true;
        }
    }
}

public static class MatcherExtensions
{
    public static Matcher<TMatch> Match<TMatch>(this TMatch matchObj)
    {
        return new Matcher<TMatch>(matchObj);
    }
}

OTHER TIPS

This is the approach I normally use. It may be slightly faster than checking the type and then casting (I have no proof of this).

foreach (Item ThisItem in TheseItems)
{
    //Display properties of Item instance “ThisItem” (Excluded for ease of reading)

    var computer = ThisItem as Computer;
    if (computer != null)
    {
         //Display distinct properties of Computer instance “ThisItem”
    }
}

Tell, don't ask.

Don't ask ThisItem for its properties so you can write them, tell it to write them for you

foreach (Item ThisItem in TheseItems)
{
    ThisItem.DisplayProperties(Console.out);
}

Then, make DisplayProperties() virtual, and overload it in Computer to include the properties exclusive to it.

Yes, just inside your IF clause, cast to your derived class and the properties will be available.

foreach (Item ThisItem in TheseItems)
{
    //Display properties of Item instance “ThisItem” (Excluded for ease of reading)

    if (ThisItem is Computer)
    {
       var ThisComputer = (Computer) ThisItem;
       Display(ThisComputer.CPU);
       //etc
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top