Click here to Skip to main content
15,910,210 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hey guys,

I have an ArrayList "inventory" that is populated with a variety of "items" that are of different, user-defined types. All of these items, regardless of type, have a member variable that is a private String _description. The member variable is a backing store for a property of the same name - Description. Here is an example of an item:
public class Weapon
{ 
private String _description;

public Weapon (String description)
{
_description = description;
}
public Description{get; set;}
}


What I need to do is stuff a series of "item" objects that are initialized through their constructor to different descriptions and then call those descriptions through a foreach loop to be printed to a multi-line textbox.

foreach(var object in inventory)
{

}


But I honestly don't know what to do in order to drill down to the objects that are held in ArrayList and access each object's property to print.

The idea behind this is so that a client can poll for the contents of the inventory and have them printed out on the screen without knowing the number or type of item in the inventory.

Any help would be appreciated.
Posted
Updated 20-May-11 11:43am
v2

What you should do is create an Interface and have it expose the Description Property. Then have every Class you want in your Array Implement this Interface. Fill your array with Objects that Implement your Interface and you can simply call the Description Property because they all have it in common :)

C#
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IItem[] inventory = new IItem[3];
            inventory[0] = new Weapon("Sword");
            inventory[1] = new CoffeeMachine("Senseo");
            inventory[2] = new Weapon("Spear");

            foreach (IItem item in inventory)
            {
                Console.WriteLine(item.Description);
            }

            Console.ReadKey();
        }
    }

    interface IItem
    {
        string Description { get; }
    }

    class Weapon : IItem
    {

        private string _description;

        public Weapon(string description)
        {
            _description = description;
        }

        public string Description
        {
            get { return _description; }
        }

        public void HitInTheHead()
        {
            // Do Something.
        }
    }

    class CoffeeMachine : IItem
    {

        private string _description;

        public CoffeeMachine(string description)
        {
            _description = description;
        }

        public string Description
        {
            get { return _description; }
        }

        public void MakeCoffe()
        {
            // Do Something.
        }
    }
}


Notice the Interface IItem. Both Weapon and CoffeeMachine Implement this Interface. You can now make an Array (why not use Generic List[^]?) of IItem and put anything in it that Implements IItem. You can then iterate through the items and access the one thing they all have in common: the Description Property they MUST Implement because of the Interface :)
Also notice that you cannot get the MakeCoffee and HitInTheHead Methods this way. Your Array only knows that its items are of type IItem and IItem only has the Description Property.
The code above is a working Console App. You can copy/paste it to test.
Good luck!
 
Share this answer
 
v2
Comments
Isaiah83 20-May-11 19:13pm    
I know of the power behind interfaces, and I can understand design pattern diagrams that use them (i.e Strategy Pattern) but I have always had a hard time visualizing them in my head, within my own projects. One thing I get tripped up on when thinking about an interface is the use of the word "expose". Can you give an explanation of this?
Sander Rossel 20-May-11 20:00pm    
Well, Methods in a Class can have different levels of accessibility. For example, a Private Method can only be accessed from within the Class and a Public Method can be accessed from an instance of your Class. Shared can be accessed from everywhere and Friend only in the same Assembly. This is called Encapsulation. Methods are exposed at different levels. When you Implement an Interface all of its Properties and Methods automatically get the Public modifier, so when you pass an instance of a Class that Implements an Interface to a variable that expects that Interface only the Interface Methods get exposed. This is also true for Inheritance.
Try for example the following:

Object obj = new TextBox;
obj.Text // This gives an error at design time.

You can assign a TextBox to an Object (a TextBox IS an Object), but an Object cannot expose the Text Property of the TextBox, because that is simply not a part of the Object.
Hope that cleared it up a bit.
And thanks for upvoting and accepting my Solution :)
Isaiah83 20-May-11 23:27pm    
Thank you for the extra time you took in preparring this explanation. One last question, if oyu dont mind: Classes that use an interface don't worry about the implementation behind the methods the interface exposes right?
Sander Rossel 21-May-11 4:26am    
That's right. You could have your Weapon Class do some cool rocket science and your CoffeeMachine do nothing, as long as they both return a String (as they are obligated by the Interface).
Isaiah83 23-May-11 14:59pm    
I noticed you named the Array after the Interface (IItem) was this intended? Or does the name not matter here?
Hi,

You said each item has Decription property. so one way is to have an interface and each of your item, impelemtns that interface. some thing like this:

C#
public interface ISameDescription
{
string Description {get;set;}
}

public class Weapon:ISameDescription
{
private String _description;

public Weapon (String description)
{
_description = description;
}
public Description{get{} set{}}
}


Now in your foreach statement you can have something like:
foreach(ISameDescription o in inventory)
{
 // To Do something with o.Description
}


if you don't wish to change your code, you can take advantage of invoke.
some thing like this:
foreach(object o in inventory)
{
  o.GetType().InvokeMember("Description", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Public, null, o, null);
}



hope this can help you.
 
Share this answer
 
v3
Comments
Apfelmuuus 20-May-11 18:48pm    
Why do you use typecasting? this leeds to bad performance. I'd use an ISameDescription array.
Sander Rossel 20-May-11 20:01pm    
I agree with Apfelmuuus. What you are doing makes no sense. Why would you go through all the trouble of creating an Interface if you are going to Invoke a Property using Reflection?
aidin Tajadod 23-May-11 15:00pm    
Apfelmuuus, your are right, I changed the answer! thanks.
aidin Tajadod 23-May-11 15:01pm    
Naeling, what Apflemuuus said is different. the invoke is another solution. I did not mean to do both!
I guess I might have been missing something, but I think this is as simple as:

for(int i=0; i < inventory.Count; i++){
    Console.Write("{0}", inventory[i].Description);
}


Obviously you would need to change Console.Write to the print method you use.
 
Share this answer
 
Comments
Sander Rossel 20-May-11 18:32pm    
That will not work if inventory[0] is of the Type Weapon and inventory[1] is of the Type SomethingElse. The OP is currently filling his Array with Objects and an Object does not have a Description Property. See my solution for more details.
pawdlk 20-May-11 18:34pm    
OK, Thanks for explaining. It looks that I have just posted it too fast without reviewing. :)
I guess polimorphism would be a good solution. Create a superior class called Item or something else. This class should contain a field Description and a function ShowDescription().
Every item of the inventory must inherit the Item class and override the function ShowDescription(). Then define an Item array and call the function ShowDescription().
public class Item
{
   protected string description;
   public virtual string ShowDescription()
   {
       //You can place a standard description here
   }
}

public class Weapon: Item
{

   public Weapon(string descr)
   {
       this.description = descr;
   }

   public override string ShowDescription()
   {
       return description;
   }
}

// within your main procedure or somewhere else:

Item[] inventory; // Define the array and instantiate it as you like it...

foreach (Item i in inventory)
{
   textbox.Text += i.ShowDescription() + "\r\n";
}


Edit:
Using an Interface or a superior class both works. Using a superior class would improve performance, using an Interface would allow to inherit from a different class so check the advantages and disadvantages of both and choose what you prefer.
EndEidt.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900