Solved

Instantiating an ICollection

Posted on 2004-04-21
7
925 Views
Last Modified: 2008-02-01
In the line marked ** I would like to instantiate a container supporting ICollection. I don't want to hardcode a choice of container here. I'd like the container choice to be something that can be changed without changing the code in the class. I was thinking of calling a container factory class method on an external class to get an instantiated ICollection but I'm not sure I have this well thought out.

class foo 'basically a list of lists.
  private _containerOfContainers : IDictionary

  public sub addItem(sKey, sValue)
   
   if not _containerOfContainers.contains(sKey) then
        dim oNewChildContainer as ICollection
**        oNewChildContainer = new ???
       _containerOfContainers.Add(sKey, oNewChildContainer )
    endif
   _containerOfContainers(sKey).Add(sValue);

  end sub

Perhaps something like:

Public class AbstractContainerProvider {
  public shared ConcreteContainerProvider;
  public function ProvideNewContainer() as Icollection {
   return ConcreteContainerProvider._ProvideNewContainer();
  };
 
 protected mustoverride function _ProvideNewContainer();

end class

public class ConcreteContainerProviderHashTable implements AbstractContainerProvider
 protected function _ProvideNewContainer() {
  return new HashTable();
 }

This would be used as follows:
  AbstractContainerProvider.ConcreteContainerProvider = new  ConcreteContainerProviderHashTable()

and my addItem method would then call the abstract factory method to get a new container:

  oNewChildContainer = AbstractContainerProvider.ProvideNewContainer();

That should mean I can change the concrete container used without recompiling my foo class.

Comments please.
0
Comment
Question by:monosodiumg
  • 5
  • 2
7 Comments
 
LVL 22

Expert Comment

by:_TAD_
ID: 10879313


Set it to null.   Then when you decide which object to set it to, you can do that without a problem.


If null doesn't work for some reason (you can't add a null value), then use a generic object

oNewChildContainer = new Object();
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10879396

oh wait....  what was I thinking, oNewChildContainer is an ICollection object so you need something that inherits ICollection.

forget the last piece about 'new Object()'
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10879568


Why not just create a new object that inherits from ICollection?

As long as you pull the data out using ICollection and enumerate through it, it doesn't really matter what kind of object you use.

// Hash Table
                  Hashtable myHash = new Hashtable();
                  myHash.Add("1","One");
                  myHash.Add("2","Two");
                  ICollection col1 = myHash;
// Array List            
                  ArrayList myList = new ArrayList();
                  myList.Add("Three");
                  myList.Add("Four");
                  ICollection col2 = myList;

                  Console.WriteLine(col1.Count.ToString());
                  Console.WriteLine(col2.Count.ToString());

They both work exactly the same way.
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
LVL 22

Expert Comment

by:_TAD_
ID: 10879853


Here is a generic setup which shows how you can use any generic object as long as it inherits ICollection.




                  Hashtable myHash = new Hashtable();
                  myHash.Add("HT1","HT One");
                  myHash.Add("HT2","HT Two");
                  myHash.Add("HT3","HT Three");
                  myHash.Add("HT4","HT Four");
                  
                  ArrayList myList = new ArrayList();
                  myList.Add("AL 1");
                  myList.Add("AL 2");
                  myList.Add("AL 3");
                  myList.Add("AL 4");
                  
//Create ICollection object
                  ICollection ic;
                  if (DateTime.Now.Second%2>0)
                        ic = myList;    // Array List
                  else
                        ic = myHash;  // Hash Table

                  IEnumerator ie = ic.GetEnumerator();
                  


In all collection objects that I know of, all data is either stored directly into the collection (using an integer to enumerate through the collection), or the collection enumerator is stored as a dictionary entry)  The following handles both types.




                  ie.MoveNext();
                  for(int i=0;i<ic.Count;i++)
                  {
                        if (ie.Current.GetType()==typeof(DictionaryEntry))
                              Console.WriteLine(((DictionaryEntry) ie.Current).Value.ToString());
                        else
                              Console.WriteLine(ie.Current.ToString());

                        ie.MoveNext();
                  }
0
 
LVL 12

Author Comment

by:monosodiumg
ID: 10880237
_TAD_,
I don't understand how your posts address the problem. Reread my first paragraph. It requires the you be able to supply different containers withouth changing the existing code.
If I go your way (section starting //Create ICollection object
) and  next year come up with MySuperCoolCollection that supports ICollection, I would have to change the code and recompile in order to be able to use it. There are 100s of classes out there that support ICollection. Writing an extensive list if..then.. tree also means importing all the classes that are mentioned in that tree. The number of dependencies is then huge and is any of the classes chamge I would have to recompile.
I'm looking for a way for avoiding this.

I've come up with the solution below but I'm not very confident about it. It does seem to work. It allows you to come up new collections and my collection using class cn use these without recompilation.

Public Interface ICollectionGenerator
  Function GenerateICollection() As ICollection
End Interface

Public Class ICollectionGeneratorHashtable
  Implements ICollectionGenerator
  Private _ncapacity As Integer = -1
  Private _snglLoadFactor As Single = -1.0

  Public Sub New()
    _ncapacity = -1
    _snglLoadFactor = -1.0
  End Sub

  Public Sub New(ByVal nCapacity As Integer)
    _ncapacity = nCapacity
    _snglLoadFactor = -1
  End Sub

  Public Sub New(ByVal nCapacity As Integer, ByVal snglLoadFactor As Single)
    _ncapacity = nCapacity
    _snglLoadFactor = snglLoadFactor
  End Sub

  Function GenerateICollection() As ICollection Implements ICollectionGenerator.GenerateICollection
    Dim oHashTable As Hashtable
    If (_ncapacity > 0) Then
      If _snglLoadFactor > 0 Then
        oHashTable = New Hashtable(_ncapacity, _snglLoadFactor)
      Else
        oHashTable = New Hashtable(_ncapacity)
      End If
    Else
      oHashTable = New Hashtable()
    End If
    Return oHashTable
  End Function
End Class

Public Class ICollectionGeneratorArrayList
  Implements ICollectionGenerator

  Private _ncapacity As Integer = -1
  Public Sub New()
    _ncapacity = -1
  End Sub

  Public Sub New(ByVal nCapacity As Integer)
    _ncapacity = nCapacity
  End Sub

  Function GenerateICollection() As ICollection Implements ICollectionGenerator.GenerateICollection
    Dim oArrayList As ArrayList

    If (_ncapacity > 0) Then
      oArrayList = New ArrayList(_ncapacity)
    Else
      oArrayList = New ArrayList()
    End If

    Return oArrayList
  End Function

End Class

The client class now looks like this:
Public class ICollectionConsumer
  Private _ICollectionGenerator As ICollectionGenerator

  public sub New(oICollectionGenerator as ICollectionGenerator)
    _ICollectionGenerator  = oICollectionGenerator
  end sub

  public sub Foo()
   Dim MyUnknownCOllectionImplementation as ICollection = _ICollectionGenerator.GenerateICollection()
  ...
  end sub

end class

That class is instantiated with a specific ICollectionGenerator:
New Foo(new ICollectionGeneratorHashtable())
or
New Foo(new ICollectionGeneratorArrayList())
and so on.

That means I can create a new ICollectionGenerator subclass for MySuperNewCollection and I do not need to recompile Foo for Foo to be able to use it.

I suppose this is really a design pattern question. I haven't got the GoF book around otherwise I'd  probably never have asked the question. I will have it tomorrow :)
mono
 

0
 
LVL 22

Accepted Solution

by:
_TAD_ earned 250 total points
ID: 10881156

Mono>

Your proposed solution is better than the quick hack I suggested.  But as for addressing the problem...  In my experience, a collection is enumerated by one of two things, either a number or some object (usually a string, but not always).


This code:


               ie.MoveNext();
               for(int i=0;i<ic.Count;i++)
               {
                    if (ie.Current.GetType()==typeof(DictionaryEntry))
                         Console.WriteLine(((DictionaryEntry) ie.Current).Value.ToString());
                    else
                         Console.WriteLine(ie.Current.ToString());

                    ie.MoveNext();
               }


enumerated through your generic collection object.  If the collection is enumerated by number, then you can simply use ie.current.   If on the other hand the collection is enumerated by an object, then you need to take the dictionary entry of that object to pull the value.  The concept is sound, and it functions perfectly for the short example I have provided.  However, I don't know how extensible it is.  It works well for all of the .Net classes I've tried it with, but that doesn't mean it won't choke on one of your user-defined classes.
0
 
LVL 12

Author Comment

by:monosodiumg
ID: 10882626
>either a number or some object
The only thing that list excludes is Boolean so I'm not sure what the point is.

The problem I have is in instantiating the collection, not in reading it. Whatever code reads the collection will have some defnite expectations as to what that collection contains and will be cast accordingly.

As an aside, I'm not at all happy with the built-in collections because of their lack of typing. I will at some point replace those with stronlgy types collections, which will make the casts redundant but guarantee success. C#2.0 will remedy that I believe. VS2003 I think provides a built-in typed collection generator.

>In all collection objects that I know of, all data is either stored directly into the collection (using an integer to enumerate through the collection), or the collection enumerator is stored as a dictionary entry)
Youalso elsehwer ekeep referring to enumertaing by numbers. Do you mean indexing? E.g. myArray[5]? That is completly different to enumerators. The builtin Enumerators  are untype (their Current is Object). No numbers involved. I think you must be thinking of things that implement IList, where you can access an object by position. If all I have is ICollection, which by inheritance implies IEnumerable, then I can't access by position.

>doesn't mean it won't choke on one of your user-defined classes
I'm guaranteeing no choking by sticking to the interfaces.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

IP addresses can be stored in a database in any of several ways.  These ways may vary based on the volume of the data.  I was dealing with quite a large amount of data for user authentication purpose, and needed a way to minimize the storage.   …
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

932 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now