Author Topic: Creating a collection class  (Read 7429 times)

0 Members and 1 Guest are viewing this topic.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Creating a collection class
« on: July 06, 2013, 03:09:57 AM »
I have a class that will be used to manage multiple objects of a specific type, I have read that IEnumerable and IList are the appropriate interfaces to use. I have never done this and the samples I have seen only seem to gloss over the process.

I am looking for the ability to add/remove/sort/count etc. the objects from the parent.

Anyone want to volunteer to point me in the right direction?
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

BlackBox

  • King Gator
  • Posts: 3770
Re: Creating a collection class
« Reply #1 on: July 06, 2013, 04:03:53 AM »
Simply derive (inherit) your custom Type(s) from the desired Type/Interface, to access shared Properties, Methods, and Events:
Code - C#: [Select]
  1. class Foo : IEnumerable
  2. {
  3.      // constructor here
  4. }
  5.  
"How we think determines what we do, and what we do determines what we get."

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a collection class
« Reply #2 on: July 06, 2013, 04:31:31 AM »
IList implements ICollection and IEnumerable
Code - C#: [Select]
  1. namespace System.Collections.Generic
  2. {
  3.     using System;
  4.     using System.Collections;
  5.     using System.Reflection;
  6.     using System.Runtime.CompilerServices;
  7.  
  8.     public interface ICollection<T> : IEnumerable<T>, IEnumerable
  9.     {
  10.        
  11.         void Add(T item);
  12.        
  13.         void Clear();
  14.        
  15.         bool Contains(T item);
  16.        
  17.         void CopyTo(T[] array, int arrayIndex);
  18.        
  19.         bool Remove(T item);
  20.        
  21.         int Count {  get; }
  22.        
  23.         bool IsReadOnly {  get; }
  24.     }
  25.     public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
  26.     {
  27.      
  28.         int IndexOf(T item);
  29.      
  30.         void Insert(int index, T item);
  31.      
  32.         void RemoveAt(int index);
  33.        
  34.         T this[int index] {  get; set; }
  35.     }
  36. }
  37.  

If you are fine with it behaving like a list then you can simply
Code - C#: [Select]
  1.         class foo
  2.         {
  3.         }
  4.         class fooList : List<foo>
  5.         {
  6.         }
  7.  

If you want different behavior  you can encapsulate a list inside your class and implement the behavior yourself
Code - C#: [Select]
  1. class fooCollection : ICollection<foo>
  2.         {
  3.             private List<foo> foos = new List<foo>();
  4.             public void Add(foo item)
  5.             {
  6.                 foos.Add(item);
  7.             }
  8.             public void Clear()
  9.             {
  10.                 throw new NotImplementedException();
  11.             }
  12.             public bool Contains(foo item)
  13.             {
  14.                 throw new NotImplementedException();
  15.             }
  16.             public void CopyTo(foo[] array, int arrayIndex)
  17.             {
  18.                 throw new NotImplementedException();
  19.             }
  20.             public int Count
  21.             {
  22.                 get { throw new NotImplementedException(); }
  23.             }
  24.             public bool IsReadOnly
  25.             {
  26.                 get { throw new NotImplementedException(); }
  27.             }
  28.             public bool Remove(foo item)
  29.             {
  30.                 throw new NotImplementedException();
  31.             }
  32.             public IEnumerator<foo> GetEnumerator()
  33.             {
  34.                 throw new NotImplementedException();
  35.             }
  36.             System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  37.             {
  38.                 throw new NotImplementedException();
  39.             }
  40.         }
  41.  
It just depends on what you will be doing with them

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #3 on: July 08, 2013, 09:37:47 AM »
Jeff, that looks like what I want to do, although I may have complicated the issue a bit. I don't really need to manipulate the collection, I merely need to store it for later use, and do so in a way that works like a default List<T> using my class of object.

To that end, I could simply declare a List<T> and expose the public properties and methods to the user ... would that be enough? Keep in mind I would implement all of the properties and methods I needed.

Code - C#: [Select]
  1. class MyObjectCollection {
  2.     List<MyObject> _contents;
  3.  
  4.    public void Add(MyObject item)
  5.    {
  6.         _contents.Add(MyObject);
  7.    }
  8.    public int Count()
  9.    {
  10.         get
  11.         {
  12.               return _contents.Count;
  13.         }
  14.    }
  15.    public void Clear()
  16.    {
  17.        _contents.Clear();
  18.    }
  19. }
  20.  

Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

n.yuan

  • Bull Frog
  • Posts: 348
Re: Creating a collection class
« Reply #4 on: July 08, 2013, 12:41:29 PM »
Why you do a class that CONTAINS a List<T> instead of do a class that IS List<T> (that is, derive a class based on List<T>) for your simple Collection need?

If you:

class MyObjectCollection:List<MyObject>
{

}

Then the class has already the regular Add()/Remove()/Clear() methods available. You simply add your own properties/methods that List<T> do not have.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #5 on: July 08, 2013, 01:42:08 PM »
That seems to be simple enough ... it seems as though I have complicated it.

So, if I create my manager class and inherit List<T> then I don't even need to implement the properties for the collection?

This is how I hope to develop the objects.

Top level class "Manager" does all of the work. Because I use the same data to populate multiple controls and control types, I manage the collection by first creating the manager by passing a valid database connection and a control to populate.

Code - C#: [Select]
  1. objManager oMgr = New objManager(_datalayer, thisControl);
  2.  

The manager has the following functions:
Code - C#: [Select]
  1. bool LoadAll(bool active = true, string filter = "")
  2. bool LoadGroups(bool active = true, string filter = "")
  3. bool LoadOrphans(bool active = true, string filter = "")
  4. bool LoadChildren(string parent, bool active= true, string filter = "")
  5.  

The functions load the data from the database and populates the correct control with all of the data. The objects are manipulated in their own class so I can derive the necessary information from them. Also, because I need to be able to create additional objects on the fly, I need to have a collection that I can manipulate.

When I select an item in the control, the value represents the ID of the database record. This loads the object data from the database and builds the object. The object is then added to the object manager.

Code - C#: [Select]
  1. objManagedItem oManagedItem = New objManagedItem();
  2. oMgr.Items.Add(oManagedItem);
  3.  

Can I hook an event to the items in the collection to fire an internal function when it changes?
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

BlackBox

  • King Gator
  • Posts: 3770
Re: Creating a collection class
« Reply #6 on: July 08, 2013, 04:38:40 PM »
Simply derive (inherit) your custom Type(s) from the desired Type/Interface, to access shared Properties, Methods, and Events:

Why you do a class that CONTAINS a List<T> instead of do a class that IS List<T> (that is, derive a class based on List<T>) for your simple Collection need?

...

Then the class has already the regular Add()/Remove()/Clear() methods available. You simply add your own properties/methods that List<T> do not have.

That seems to be simple enough ... it seems as though I have complicated it.

So, if I create my manager class and inherit List<T> then I don't even need to implement the properties for the collection?



Correct... This is due to what's known as 'Implementation Inheritance':

Quote from: MSDN, Inheritance from a Base Class in Microsoft .NET

Inheritance Terminology

There are three types of inheritance that .NET supports: implementation, interface, and visual. Implementation inheritance refers to the ability to use a base class's properties and methods with no additional coding. Interface inheritance refers to the ability to use just the names of the properties and methods, but the child class must provide the implementation. Visual inheritance refers to the ability for a child form (class) to use the base forms (class) visual representation as well as the implemented code.

A class in .NET may inherit from a class that has already inherited from another class. In addition you may use an interface or even multiple interfaces within a class.
"How we think determines what we do, and what we do determines what we get."

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #7 on: July 08, 2013, 05:51:15 PM »
Then I don't need to do anything? Can it be that easy?
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

BlackBox

  • King Gator
  • Posts: 3770
Re: Creating a collection class
« Reply #8 on: July 08, 2013, 05:56:06 PM »
Then I don't need to do anything? Can it be that easy?

If you simply need a custom Class that inherits the properties, methods, and events of another type or interface... Yes.

What shortcomings (if any) have you experienced when implementing?

"How we think determines what we do, and what we do determines what we get."

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #9 on: July 08, 2013, 11:14:35 PM »
Well, I haven't fully implemented it yet. Right now the class works like this:

Create a new manager object passing a database connection and control in the constructor.

The user then passes a few arguments (or not) to one of the 4 methods described above and the manager retrieves the data from the database, formats it in a way that is compatable with the passed control and populates the control with the data (the control may be a ComboBox, ListBox, ListView or TreeView).

This is what the manager does on initialization. On postback, (this is a web application) the manager is instantiated with the database connection and control the same as before, but depending upon what caused the postback, the manager will either add a new item to the collection of things used to populate the control, delete an item from the collection or modify an existing item in the collection. The data is held in a transient state until the SaveAll method of the manager is called. This will then commit the objects in the collection to the database. Whether the items are saved is based upon the user's actions and the postback values.

Because this is a web application, all data is transient and exists only for the duration of the execution of the server-side code, and long enough to populate the control with the data that is displayed to the user.

I probably don't need to be as complex as I want to make these objects, but I will certainly be using this class in another application in the future, thus the ability to edit objects in the collection is of importance. Also, I will very likely be adding additional properties and methods to the objects in the collection, so creating a derived class, inherited from List<T> is also probably the way I want to go with this, not to mention that I will likely be using this class in other data object managers.

So, lets just start at the beginning.

I have an object that is created from data in the database. We will call this object "Shift" (remember this is a medical staffing and patient manager).
For each building, there may be many shifts that need to be created and displayed to the user in a ListBox, ComboBox, or perhaps a DataGrid. To keep all of the shifts in one location, I will create a "ShiftCollection" that holds all of the "Shift" objects. This collection is a simple List<Shift> and thus I am able to add/edit/delete any of the "Shift" objects in "ShiftCollection".

In my "ShiftManager" class, I will have a private variable of "ShiftCollection" (lets call it _shiftCollection). The private variable _shiftCollection will be exposed through an Items property. Now, I can instantiate my ShiftManager class with the control and database connection, then fill the _shiftCollection object with one of the four methods described in my earlier post. This will load all of the Shift objects from the database, placing each into the _shiftCollection object.

Once I have ShiftManager instantiated and filled, I can then edit the ShiftCollection through the Items property of the ShiftManager, adding, deleting or editing the contents as needed.

The only part that I am unclear with now, is how can I call the private method in ShiftManager to clear all items from the control and populate it with the new collection once the collection or an item in the collection has changed? Is there an event that is fired when the collection is modified or do I have to create my own events (for example OnShiftEdit event, then bubble up to the collection which fires an OnShiftCollectionModified event that the manager class can catch and call the correct function to update the control)?

Oh, and one final thing, if I make Items the default property, can I then access the items in the List<Shift> by like this:
Code - C#: [Select]
  1. shift Items[int index]
  2. {
  3.     get
  4.     {
  5.          return _shiftCollection[index];
  6.     }
  7.     set
  8.     {
  9.         _shiftCollection[index] = value;
  10.     }
  11. }
  12.  
  13. shift thisShift = ShiftManager.Item[n];
  14.  
« Last Edit: July 08, 2013, 11:27:57 PM by Keith™ »
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

BlackBox

  • King Gator
  • Posts: 3770
Re: Creating a collection class
« Reply #10 on: July 09, 2013, 03:02:06 AM »
Quote
The only part that I am unclear with now, is how can I call the private method in ShiftManager to clear all items from the control and populate it with the new collection once the collection or an item in the collection has changed?

Couple of things... Couldn't you simply implement an override for the Clear() Method which accepts your collection?

Also, is there a reason you chose to inherit from List<Shift>, rather than implement Shift[]? Particularly given your Items[int index] property, which would be inherited from Shift[].

I'd have to explore the event inheritance (if any). *not sure*
"How we think determines what we do, and what we do determines what we get."

fixo

  • Guest
Re: Creating a collection class
« Reply #11 on: July 09, 2013, 04:13:16 AM »
Just for your interest, here is the way to do it
dynamically, see for more:
http://codearticles.ru/articles/944

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Creating a collection class
« Reply #12 on: July 09, 2013, 08:59:12 PM »
Another nice thing about using IList is the ability to run LINQ against your object.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

BlackBox

  • King Gator
  • Posts: 3770
"How we think determines what we do, and what we do determines what we get."

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Creating a collection class
« Reply #14 on: July 10, 2013, 09:33:20 AM »
I am just starting to learn MVC 4, and maybe some else knows but I thought you could easily bind data to your controls, but I do not know enough.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #15 on: July 10, 2013, 11:25:36 PM »
I am just starting to learn MVC 4, and maybe some else knows but I thought you could easily bind data to your controls, but I do not know enough.

This isn't MVC, it is ASP and the controls that I am required to use don't bind all of the data. It merely binds the display text and display value.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating a collection class
« Reply #16 on: July 11, 2013, 07:49:23 AM »
MVC is an Architecture and can be used outside of ASP though its primary purpose is for ASP.
Revit 2019, AMEP 2019 64bit Win 10

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #17 on: July 11, 2013, 10:11:37 AM »
oh, really ... didn't know that
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

BlackBox

  • King Gator
  • Posts: 3770
Re: Creating a collection class
« Reply #18 on: July 11, 2013, 12:23:45 PM »
Out of curiosity, which collection did you choose to inherit from... List<T> (non-virtual methods), Collection<T> (virtual methods), ObservableCollection<T>, or BindingList<T>?
"How we think determines what we do, and what we do determines what we get."

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #19 on: July 11, 2013, 02:01:53 PM »
I used List<T> because it was the simplest to implement.

The structure is as follows for this specific portion of the project:
+FacilityManager
     +FacilityCollection
         +FacilityItem
             -ReportsManager
             -ContractsManager

I created several events for the facility collection that fire when List<T> changes  ... actually I just raise the event in the exposed properties and methods that modify the List<T> object. Then in FacilityManager I capture the event and add the item to my ASP control.

The FacilityManager object only exposes the methods related to reading the initial data from the database. All subsequent modifications should be done through the Items property that returns the FacilityCollection, so:
Code - C#: [Select]
  1. //instantiate the facility manager
  2. FacilityManager fm = New FacilityManager(_listControl, _datalayer);
  3. //load all the facility items the current user has access to
  4. fm.LoadAll(_currentUserID);

When the user creates a new item from data input, this happens:
Code - C#: [Select]
  1. //Create a new facility item
  2. FacilityItem fi = New FacilityItem();
  3. //set the various properties from the controls
  4. //...
  5. //Add the new FacilityItem to the FacilityCollection
  6. fm.Items.Add(fi);

At this point, FacilityCollection raises the event ItemAdded and it is captured in the FacilityManager class
Code - C#: [Select]
  1. private void _facilities_ItemAdded(object sender, ListItemArgs e)
  2. {
  3.     //Add the item to the control
  4.     _listControl.Add(sender.ToListItem);
  5. }
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating a collection class
« Reply #20 on: July 11, 2013, 03:06:36 PM »
If "Items" is a property of FacilityManager, why create an event for ItemAdded?  Why not call _listControl.Add(sender.ToListItem) in the setter?
Revit 2019, AMEP 2019 64bit Win 10

BlackBox

  • King Gator
  • Posts: 3770
Re: Creating a collection class
« Reply #21 on: July 11, 2013, 03:12:12 PM »
Knowing Keith was after certain events, is one of the reasons I asked which collection type was being inherited from... For example, the BindingList<T> type's built-in AddingNew, and ListChanged events.
"How we think determines what we do, and what we do determines what we get."

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #22 on: July 11, 2013, 04:55:15 PM »
If "Items" is a property of FacilityManager, why create an event for ItemAdded?  Why not call _listControl.Add(sender.ToListItem) in the setter?

See if this makes sense:
Code - C#: [Select]
  1. Class FacilityManager
  2. {
  3.      private FacilityCollection _fc = New FacilityCollection();
  4.      private object _listControl;
  5.  
  6.     _fc.ItemAdded += fc_ItemAdded;
  7.  
  8.      FacilityCollection property Items()
  9.      {
  10.            get
  11.            {
  12.                return _fc;
  13.            }
  14.            private set(FacilityCollection collection)
  15.            {
  16.                _fc = collection;
  17.            }
  18.     }
  19.     static void fc_ItemAdded(object sender, ListItemEventArgs e)
  20.     {
  21.         if !e.IsTransient
  22.         {
  23.             if AddItemToControl((FacilityItem)sender)
  24.             {
  25.                  //Do other work here
  26.             }
  27.         }
  28.     }
  29.  
  30.     private AddItemToControl(FacilityItem item)
  31.     {
  32.         bool success = false;
  33.         switch (typeof(item).ToString.ToLower())
  34.         {
  35.             case "ListType1":
  36.                  ListType1 _listObj = (ListType1)_listControl;
  37.                  _listObj.Add(item.ToListType1Item);
  38.                  success = true;
  39.                  break;
  40.             case "ListType2":
  41.                  ListType2 _listObj = (ListType2)_listControl;
  42.                  _listObj.Add(item.ToListType1Item);
  43.                  success = true;
  44.                  break;
  45.             case "ListType3":
  46.                  ListType3 _listObj = (ListType3)_listControl;
  47.                  _listObj.Add(item.ToListType1Item);
  48.                  success = true;
  49.                  break;
  50.             case "ListType4":
  51.                  ListType4 _listObj = (ListType4)_listControl;
  52.                  _listObj.Add(item.ToListType1Item);
  53.                  success = true;
  54.        }
  55.         return success;
  56.     }
  57. }
  58.  
  59. Class FacilityCollection
  60. {
  61.     private  List<FacilityItem> _contents;
  62.      
  63.     public event ItemAdded(object sender, ListItemEventArgs e);
  64.  
  65.     void Add(FacilityItem item)
  66.     {
  67.         _contents.Add(item) ;
  68.         ItemAdded(item, New ListItemEventArgs(!item.HasChanges && Validate(item.GUID)));
  69.     }
  70. }
  71.  

There may be a better way of dealing with what I am doing, but if there is, I don't see it.

I could do as you suggest and simply add the new FacilityItem directly to the _listControl from the FacilityManager, but I would have to create another function to do it .. and then I would still have to add the item to the FacilityCollection.

I suppose I could simply let FacilityCollection inherit List<FacilityItem> and then manipulate it as though FacilityCollection is nothing more than a List<FacilityItem> with some additional methods and properties that I define ... but I would still have to run the function to add the object to the control.

At least this way, when _contents is added to, FacilityManager knows about it and can do what it needs to do whenever the collection changes.

Unless I have completely missed the point ... and that wouldn't be unreasonable ...
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating a collection class
« Reply #23 on: July 12, 2013, 08:13:59 AM »

See if this makes sense:
Code - C#: [Select]
  1. Class FacilityManager
  2. {
  3.      private FacilityCollection _fc = New FacilityCollection();
  4.      private object _listControl;
  5.  
  6.     _fc.ItemAdded += fc_ItemAdded;
  7.  
  8.      FacilityCollection property Items()
  9.      {
  10.            get
  11.            {
  12.                return _fc;
  13.            }
  14.            private set(FacilityCollection collection)
  15.            {
  16.                _fc = collection;
  17.            }
  18.     }
  19.     static void fc_ItemAdded(object sender, ListItemEventArgs e)
  20.     {
  21.         if !e.IsTransient
  22.         {
  23.             if AddItemToControl((FacilityItem)sender)
  24.             {
  25.                  //Do other work here
  26.             }
  27.         }
  28.     }
  29.  
  30.     private AddItemToControl(FacilityItem item)
  31.     {
  32.         bool success = false;
  33.         switch (typeof(item).ToString.ToLower())
  34.         {
  35.             case "ListType1":
  36.                  ListType1 _listObj = (ListType1)_listControl;
  37.                  _listObj.Add(item.ToListType1Item);
  38.                  success = true;
  39.                  break;
  40.             case "ListType2":
  41.                  ListType2 _listObj = (ListType2)_listControl;
  42.                  _listObj.Add(item.ToListType1Item);
  43.                  success = true;
  44.                  break;
  45.             case "ListType3":
  46.                  ListType3 _listObj = (ListType3)_listControl;
  47.                  _listObj.Add(item.ToListType1Item);
  48.                  success = true;
  49.                  break;
  50.             case "ListType4":
  51.                  ListType4 _listObj = (ListType4)_listControl;
  52.                  _listObj.Add(item.ToListType1Item);
  53.                  success = true;
  54.        }
  55.         return success;
  56.     }
  57. }
  58.  
  59. Class FacilityCollection
  60. {
  61.     private  List<FacilityItem> _contents;
  62.      
  63.     public event ItemAdded(object sender, ListItemEventArgs e);
  64.  
  65.     void Add(FacilityItem item)
  66.     {
  67.         _contents.Add(item) ;
  68.         ItemAdded(item, New ListItemEventArgs(!item.HasChanges && Validate(item.GUID)));
  69.     }
  70. }
  71.  

There may be a better way of dealing with what I am doing, but if there is, I don't see it.

I could do as you suggest and simply add the new FacilityItem directly to the _listControl from the FacilityManager, but I would have to create another function to do it .. and then I would still have to add the item to the FacilityCollection.

I suppose I could simply let FacilityCollection inherit List<FacilityItem> and then manipulate it as though FacilityCollection is nothing more than a List<FacilityItem> with some additional methods and properties that I define ... but I would still have to run the function to add the object to the control.

At least this way, when _contents is added to, FacilityManager knows about it and can do what it needs to do whenever the collection changes.

Unless I have completely missed the point ... and that wouldn't be unreasonable ...

This looks different than what I commented on before but this is how I would write this.

Code - C#: [Select]
  1. public class FacilityManager
  2. {
  3.     private var FacilityCollection = new List<FacilityItem>();
  4.     private var _listControl = new List<object>();
  5.  
  6.     public AddItemToControl(FacilityItem item)
  7.     {
  8.         FacilityCollection.Add(item);
  9.  
  10.         bool success = false;
  11.         switch (typeof(item).ToString.ToLower())
  12.         {
  13.             case "listtype1":
  14.                  _listControl.Add(item.ToListType1Item);
  15.                  success = true;
  16.                  break;
  17.             case "listtype2":
  18.                  _listControl.Add(item.ToListType1Item);
  19.                  success = true;
  20.                  break;
  21.             case "listtype3":
  22.                  _listControl.Add(item.ToListType1Item);
  23.                  success = true;
  24.                  break;
  25.             case "listtype4":
  26.                  _listControl.Add(item.ToListType1Item);
  27.                  success = true;
  28.        }
  29.        
  30.         If (success)
  31.         {
  32.              //Do other work here
  33.          }
  34.     }
  35. }
  36.  

Call it like this
Code - C#: [Select]
  1. var fc = new FacilityManager();
  2. var item = new FacilityItem();
  3. fc.AddItemToControl(item);
  4.  

No need to create another class just to hold a List<T> with no added functionality so you could ditch FacilityCollection.  If your needing to Get FacilityCollection just expose it as a Property instead of a private member.  The entire method AddItemToControl looks suspicious but without knowing what your doing with the results its hard to suggest another way of doing it. Programming is like skinning cats this is just how I would do it.
Revit 2019, AMEP 2019 64bit Win 10

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #24 on: July 13, 2013, 10:45:48 AM »
I see what you are talking about. However, the underlying issue is that there are at least 17 different scenarios where the collection of objects is to be used is other classes.

Also, I don't know if you did it intentionally, but the _listControl isn't a List<object> and I'm pretty sure it wouldn't work in my application.

For most of the objects where we are showing the data, there is no implied casting. The controls that we are using won't work in that manner, so our objects must be cast to the object type needed for the control (in this case the FacilityItem object). For example, when we use a checked treeview, we have to utilize the ToCheckableTreeNode method of FacilityItem ... and inside FacilityItem there is other magic that goes on as well. It simplifies the task of populating a myriad of different objects with the data when the object type being populated is not known at design time.

One of the things I didn't talk about in my last couple posts is that the Add method isn't the only way to add objects to the FacilityManager collection of FacilityItem. When the FacilityManager is instantiated, it loads all of the items from the database that meet the criteria passed in the constructor. Those items, as well as any user created items, are displayed in a control ... which control and which type of control is entirely dependent upon the page the user is viewing. In some pages the objects in the manager are displayed in multiple locations because a property in one object may have a loose connection with another object. That is figured out in the code and displayed differently for the user.

I know that I can add a List<FacilityItem> to the FacilityManager class, however, because that collection has other internal methods (I've shown only a simplified version here) and the collection needs to be modular.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #25 on: July 18, 2013, 03:45:57 PM »
I've rethought my collection class and I can see where it would make sense to just implement List<T> in my manager class, however, today I ran across a problem that seems to beg for a collection. Is there any way to get around it other than what feels like a clumsy approach?

This is the basic class info:
Code - C#: [Select]
  1. public class StaffManager : List<StaffItem>
  2. {
  3.       pubic overrides string ToString()
  4.       {
  5.            stringbuilder sb = new stringbuilder();
  6.            for (int i = 0; i < this.Items.Count ; i++)
  7.            {
  8.                     if (i != 0)
  9.                     {
  10.                          sb.append(", ");
  11.                     }
  12.                     sb.append(this.Item(i).ToString());
  13.            }
  14.            return sb.ToString();
  15.       }
  16. }
  17.  
  18. public class StaffItem
  19. {
  20.      private string _longName;
  21.      private List<DisciplineItem> _disciplines;
  22.  
  23.      public overrides string ToString()
  24.      {
  25.          return _longName();
  26.      }
  27.  
  28.      public List<DisciplineItem> Disciplines()
  29.      {
  30.            get
  31.            {
  32.                  return _disciplines;
  33.            }
  34.      }
  35.  
  36.     public string DisciplinesAsString()
  37.    {
  38.          get
  39.         {
  40.            stringbuilder sb = new stringbuilder();
  41.            for (int i = 0; i < _disciplines.Count ; i++)
  42.            {
  43.                     if (i != 0)
  44.                     {
  45.                          sb.append(", ");
  46.                     }
  47.                     sb.append(this.Item(i).ToString());
  48.            }
  49.            return sb.ToString();
  50.         }
  51.     }
  52. }

What is at issue is that I need to return a delimited string containing all of the certified disciplines for a staff member.

I could just get the List<DisciplineItem> object and iterate through it in the code, but I will be doing this multiple times. It seems logical to house it in the object itself. Placing the code inside the StaffItem makes a little more sense because I only have to write the code once, where it applies to a staff member. However, multiple classes will have a List<DisciplineItem> and I would have to write code in each of them to do the exact same thing.

In this case, I think it makes sense to create a collection class:
Code - C#: [Select]
  1. public class DisciplineCollection : List<DisciplineItem>
  2. {
  3.       pubic overrides string ToString()
  4.       {
  5.            stringbuilder sb = new stringbuilder();
  6.            for (int i = 0; i < this.Items.Count ; i++)
  7.            {
  8.                     if (i != 0)
  9.                     {
  10.                          sb.append(", ");
  11.                     }
  12.                     sb.append(this.Item(i).ToString());
  13.            }
  14.            return sb.ToString();
  15.       }
  16. }

Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Creating a collection class
« Reply #26 on: July 19, 2013, 07:53:54 AM »
You can Join any IEnumerable like so.

Code - C#: [Select]
  1. var Items = new List<Item>();
  2. var joinedString = string.Join(", ", Items);
  3.  

That does the exact same thing as your override ToString().

Revised to use Items instead of StafffItem.
« Last Edit: July 19, 2013, 08:03:04 AM by MexicanCustard »
Revit 2019, AMEP 2019 64bit Win 10

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Creating a collection class
« Reply #27 on: July 19, 2013, 08:46:23 AM »
:shock:
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

CADDOG

  • Newt
  • Posts: 82
  • wishbonesr
Re: Creating a collection class
« Reply #28 on: July 22, 2013, 10:21:23 PM »
Custard's example needs to be further qualified, as that process will only work on List<string>.
Code: [Select]
string.join(", ", Items.Select(str => str.[strprop]))
...otherwise you might get something like namespace.FacilityItem, namespace.FacilityItem... due to System.Object.ToString() that you must override.

Food for thought.
http://msdn.microsoft.com/en-us/ms182142.aspx

As Custard said
Quote from: Custard
skinning cats

Here's some psudo of what it might look like with collectionbase.  Making many assumptions though. I just picked one of the versions posted.
NOTE:  I wouldn't put the GetDisciplineList, rather just implement a ToString() override in the FacilityItem.  Appropriately using LINQ on the outside of the class is sufficient.
Code: [Select]
public class FacilityItem
{
private string name;
public string Name
{ get {return name;}
set {name = value;}
}
private string discipline;
public string Discipline
{ get { return discipline;}
  set { discipline = value;}
}
public FacilityItem()
{}
public FacilityItem(string facilityName)
{ name = facilityName;}
}
public class Facility : CollectionBase
{
#region properties
public string GetDisciplineList()
{
return string.Join(", ", List.OfType<FacilityItem>().ToList().Select(str => str.Name.ToString()));
}

//enable int indexing
public FacilityItem this[int itemIndex]
{
get { return (FacilityItem)List[itemIndex]; }
set { List[itemIndex] = value; }
}
//enable string indexing
public FacilityItem this[string itemIndex]
{
get
{
foreach (FacilityItem item in List)
{
if (item.Name == itemIndex)
return item;
}
return null;
}
}
#endregion

#region initialization methods
//no facilityitem needed, string or otherwise
public FacilityList()
{}
//usefull in new from cloning
public FacilityList(IEnumerable<FacilityItem> initialItems)
{
foreach (FacilityItem item in initialItems)
Add(item);
}
//alternative, usefull if creating several facilities the same
public FacilityList(IEnumerable<string> initialItems)
{
foreach (string item in initialItems)
List.Add(item);
}
//single initializer for facilitylist
public FacilityList(string initialItem)
{
List.Add(initialItem);
}
#endregion

#region maintenance overrides
//strongly typed maintenance make API usable
public void Add(FacilityItem newItem)
{ List.Add(newItem); }
public void Add(string newItem)
{ List.Add(new FacilityItem(newItem)); }
public FacilityItem Add(string newItem)
{
FacilityItem it = new FacilityItem(newItem);
List.Add(it);
return it;
}
public void Remove(FacilityItem oldItem)
{ List.Remove(oldItem); }
public void Remove(string oldItem)
{ List.Remove(oldItem); }
//deep cloning could go here if needed
#endregion
}

Here's an example of a Student->Grades->Grade heirarchal class..  Again, something you might find usefull in class design.

Code: [Select]
public class Grade
{
private int score;
public int Score
{
get
{
return score;
}
set
{
if (value <= 100 && value >= 0)
score = value;
else
throw (new ArgumentOutOfRangeException("Score", value,
"Please enter a percentage based grade [0~100]"));
}
}

//public Grade(Grade newGrade)
//{
//    score = newGrade.Score;
//}
//private Grade()
//{
//}
public override string ToString()
{
return Score.ToString();
}
}

public class Grades : CollectionBase
{
public double Average()
{
int tally = 0;
foreach (Grade storedGrades in List)
{
tally += storedGrades.Score;
}
return Convert.ToDouble(tally) / List.Count;
}
public void Add(Grade newGrade)
{
List.Add(newGrade);
}
public void Remove(Grade oldGrade)
{
List.Remove(oldGrade);
}
public Grade this[int gradeIndex]
{
get
{
return (Grade)List[gradeIndex];
}
set
{
List[gradeIndex] = value;
}
}
}

public class Student
{
private Grades grades = new Grades();  //not sure if the Grades collection should be a property?
//private Grade[] grades;
private string studentName;
//public readonly string studentName;
public Grades Grades
{
get
{
return this.grades;
}
}
public string StudentName
{
get
{
return studentName;
}
set
{
StudentName = studentName;
}
}

public Student(string newStudentName)
{
studentName = newStudentName;

}
private Student()
{
}
}

EDIT1: c# formatting = no scroll bars
EDIT2: Apparently System.Collections.CollectionBase was superceded by Generics when they were introduced in 2.0  eecch.  I took a shot at it, but I have a little to learn about them.  I attempted ICollectionT...  attempted.
« Last Edit: July 24, 2013, 09:51:10 PM by CADDOG »