Solved

Instantiating an ICollection

Posted on 2004-04-21
7
924 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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Visual Studio Code with .Net Core 5 16
.NET Error 7 42
Loop through Multiple Processes Async 2 17
Saveas need to save a copy 16 11
Summary Displaying images in RichTextBox is a common requirement with limited solutions available. Pasting through clipboard or embedding into RTF content only support static images.  This article describes how to insert Windows control objects int…
In my previous article (http://www.experts-exchange.com/Programming/Languages/.NET/.NET_Framework_3.x/A_4362-Serialization-in-NET-1.html) we saw the basics of serialization and how types/objects can be serialized to Binary format. In this blog we wi…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

760 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

21 Experts available now in Live!

Get 1:1 Help Now