How to implement IDictionary with <int, MyClass> members for custom Collection Object?

  • Thread starter Thread starter Rich P
  • Start date Start date
R

Rich P

I found

public class SimpleDictionary : IDictionary

for creating a custom collection object at this site:

http://msdn.microsoft.com/en-us/library/system.collections.idictionary.a
spx

The following is a simple class called MyClass (followed by
SimpleDictionary : IDictionary). I can add MyClass objects to
SimpleDictionary as is. But if I add the following members to
IDictionary <int, MyClass> -- then my test app complains that I am not
implementing the members. How do I emplement these members <int,
MyClass> ?


public class MyClass
{
public int EmpID;
public string EmpName;

public MyClass(int i, string s)
{
EmpID = i;
EmpName = s;
}
}


// This class implements a simple dictionary using an array of
DictionaryEntry objects (key/value pairs).
public class SimpleDictionary : IDictionary <int, MyClass>
{
// The array of items
private DictionaryEntry[] items;
private Int32 ItemsInUse = 0;

// Construct the SimpleDictionary with the desired number of items.
// The number of items cannot change for the life time of this
SimpleDictionary.
public SimpleDictionary(Int32 numItems)
{
items = new DictionaryEntry[numItems];
}

#region IDictionary Members
public bool IsReadOnly { get { return false; } }
public bool Contains(object key)
{
Int32 index;
return TryGetIndexOfKey(key, out index);
}
public bool IsFixedSize { get { return false; } }
public void Remove(object key)
{
if (key == null) throw new ArgumentNullException("key");
// Try to find the key in the DictionaryEntry array
Int32 index;
if (TryGetIndexOfKey(key, out index))
{
// If the key is found, slide all the items up.
Array.Copy(items, index + 1, items, index, ItemsInUse -
index - 1);
ItemsInUse--;
}
else
{
// If the key is not in the dictionary, just return.
}
}
public void Clear() { ItemsInUse = 0; }
public void Add(object key, object value)
{
// Add the new key/value pair even if this key already exists in
the dictionary.
if (ItemsInUse == items.Length)
throw new InvalidOperationException("The dictionary cannot
hold any more items.");
items[ItemsInUse++] = new DictionaryEntry(key, value);
}
public ICollection Keys
{
get
{
// Return an array where each item is a key.
Object[] keys = new Object[ItemsInUse];
for (Int32 n = 0; n < ItemsInUse; n++)
keys[n] = items[n].Key;
return keys;
}
}
public ICollection Values
{
get
{
// Return an array where each item is a value.
Object[] values = new Object[ItemsInUse];
for (Int32 n = 0; n < ItemsInUse; n++)
values[n] = items[n].Value;
return values;
}
}
public object this[object key]
{
get
{
// If this key is in the dictionary, return its value.
Int32 index;
if (TryGetIndexOfKey(key, out index))
{
// The key was found; return its value.
return items[index].Value;
}
else
{
// The key was not found; return null.
return null;
}
}

set
{
// If this key is in the dictionary, change its value.
Int32 index;
if (TryGetIndexOfKey(key, out index))
{
// The key was found; change its value.
items[index].Value = value;
}
else
{
// This key is not in the dictionary; add this key/value
pair.
Add(key, value);
}
}
}
private Boolean TryGetIndexOfKey(Object key, out Int32 index)
{
for (index = 0; index < ItemsInUse; index++)
{
// If the key is found, return true (the index is also
returned).
if (items[index].Key.Equals(key)) return true;
}

// Key not found, return false (index should be ignored by the
caller).
return false;
}
private class SimpleDictionaryEnumerator : IDictionaryEnumerator
{
// A copy of the SimpleDictionary object's key/value pairs.
DictionaryEntry[] items;
Int32 index = -1;

public SimpleDictionaryEnumerator(SimpleDictionary sd)
{
// Make a copy of the dictionary entries currently in the
SimpleDictionary object.
items = new DictionaryEntry[sd.Count];
Array.Copy(sd.items, 0, items, 0, sd.Count);
}

// Return the current item.
public Object Current { get { ValidateIndex(); return
items[index]; } }

// Return the current dictionary entry.
public DictionaryEntry Entry
{
get { return (DictionaryEntry)Current; }
}

// Return the key of the current item.
public Object Key { get { ValidateIndex(); return
items[index].Key; } }

// Return the value of the current item.
public Object Value { get { ValidateIndex(); return
items[index].Value; } }

// Advance to the next item.
public Boolean MoveNext()
{
if (index < items.Length - 1) { index++; return true; }
return false;
}

// Validate the enumeration index and throw an exception if the
index is out of range.
private void ValidateIndex()
{
if (index < 0 || index >= items.Length)
throw new InvalidOperationException("Enumerator is
before or after the collection.");
}

// Reset the index to restart the enumeration.
public void Reset()
{
index = -1;
}
}
public IDictionaryEnumerator GetEnumerator()
{
// Construct and return an enumerator.
return new SimpleDictionaryEnumerator(this);
}
#endregion

#region ICollection Members
public bool IsSynchronized { get { return false; } }
public object SyncRoot { get { throw new NotImplementedException();
} }
public int Count { get { return ItemsInUse; } }
public void CopyTo(Array array, int index) { throw new
NotImplementedException(); }
#endregion

#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
// Construct and return an enumerator.
return ((IDictionary)this).GetEnumerator();
}
#endregion
}







Rich
 
I found

public class SimpleDictionary : IDictionary

for creating a custom collection object at this site:

http://msdn.microsoft.com/en-us/library/system.collections.idictionary.aspx

The following is a simple class called MyClass (followed by
SimpleDictionary : IDictionary). I can add MyClass objects to
SimpleDictionary as is. But if I add the following members to
IDictionary<int, MyClass> -- then my test app complains that I am not
implementing the members. How do I emplement these members<int,
MyClass> ?

You are not making it easy for us - since you are not providing
the exact error message.

But a quick glance at the code indicates that some of the
methods implementing the interfaces need some generic types.

public ICollection<int> Keys

public ICollection<MyClass> Values

IEnumerator<int> IEnumerable.GetEnumerator()

Arne
 
But a quick glance at the code indicates that some of the
methods implementing the interfaces need some generic types.

public icollection<int> Keys

public icollection<myclass> Values

ienumerator<int> IEnumerable.GetEnumerator()

Arne
<

Thank you for your reply. I made a few changes (like class name to
MyClassCollection. I also applied your suggestions above. I made
everything that said key and <int> and everything that said Value
<MyClass>. I am getting 17 errors. Following are 3 of the errors (one
error is common to about 10 of the errors, the 3rd error is self
explanatory) and a relisting of my collection class with the changes
that I have made thus far (note: the whole point of this exercise is to
learn how to implement interfaces and interfaces with members):

Error 1 -- 'InterfaceDictionary.MyClassCollection' does not implement
interfacemember 'System.Collections.IEnumerable.GetEnumerator()'.
'InterfaceDictionary.MyClassCollection.GetEnumerator()' cannot implement
'System.Collections.IEnumerable.GetEnumerator()' because it does not
have the matching return type of 'System.Collections.IEnumerator'.

Error 2 -- 'InterfaceDictionary.MyClassCollection' does not implement
interface member
'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyVa
luePair<int,InterfaceDictionary.MyClass>>.GetEnumerator()'.
'InterfaceDictionary.MyClassCollection.GetEnumerator()' cannot implement
'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyVa
luePair<int,InterfaceDictionary.MyClass>>.GetEnumerator()' because it
does not have the matching return type of
'System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyVa
luePair<int,InterfaceDictionary.MyClass>>'.

Error 11 -- 'IEnumerable.GetEnumerator' in explicit interface
declaration is not a member of interface


public class MyClassCollection : IDictionary <int, MyClass>
{

// The array of items
private DictionaryEntry[] items;
private Int32 ItemsInUse = 0;

//// Construct the SimpleDictionary with the desired number of items.
//// The number of items cannot change for the life time of this
SimpleDictionary.
public MyClassCollection(Int32 numItems)
{
items = new DictionaryEntry[numItems];
}

#region IDictionary Members
public bool IsReadOnly { get { return false; } }
public bool Contains(int key)
{
Int32 index;
return TryGetIndexOfKey(key, out index);
}
public bool IsFixedSize { get { return false; } }
public void Remove(int key)
{
if (key == null) throw new ArgumentNullException("key");
// Try to find the key in the DictionaryEntry array
Int32 index;
if (TryGetIndexOfKey(key, out index))
{
// If the key is found, slide all the items up.
Array.Copy(items, index + 1, items, index, ItemsInUse - index -
1);
ItemsInUse--;
}
else
{
// If the key is not in the dictionary, just return.
}
}
public void Clear() { ItemsInUse = 0; }
public void Add(int key, MyClass value)
{
// Add the new key/value pair even if this key already exists in the
dictionary.
if (ItemsInUse == items.Length)
throw new InvalidOperationException("The dictionary cannot hold
any more items.");
items[ItemsInUse++] = new DictionaryEntry(key, value);
}
public ICollection<int> Keys
{
get
{
// Return an array where each item is a key.
//int[] keys = new int[ItemsInUse];
int[] keys = new int[ItemsInUse];
for (Int32 n = 0; n < ItemsInUse; n++)
keys[n] = items[n].Key;
return keys;
}
}
public ICollection<MyClass> Values
{
get
{
// Return an array where each item is a value.
MyClass[] values = new MyClass[ItemsInUse];
for (Int32 n = 0; n < ItemsInUse; n++)
values[n] = items[n].Value;
return values;
}
}
public int this[int key]
{
get
{
// If this key is in the dictionary, return its value.
Int32 index;
if (TryGetIndexOfKey(key, out index))
{
// The key was found; return its value.
return items[index].Value;
}
else
{
// The key was not found; return null.
return 0;
}
}

set
{
// If this key is in the dictionary, change its value.
Int32 index;
if (TryGetIndexOfKey(key, out index))
{
// The key was found; change its value.
items[index].Value = value;
}
else
{
// This key is not in the dictionary; add this key/value pair.
Add(key, value);
}
}
}
private Boolean TryGetIndexOfKey(int key, out Int32 index)
{
for (index = 0; index < ItemsInUse; index++)
{
// If the key is found, return true (the index is also returned).
if (items[index].Key.Equals(key)) return true;
}

// Key not found, return false (index should be ignored by the
caller).
return false;
}
private class MyClassEnumerator : IDictionaryEnumerator
{
// A copy of the SimpleDictionary object's key/value pairs.
DictionaryEntry[] items;
Int32 index = -1;

public MyClassEnumerator(MyClassCollection sd)
{
// Make a copy of the dictionary entries currently in the
SimpleDictionary object.
items = new DictionaryEntry[sd.Count];
Array.Copy(sd.items, 0, items, 0, sd.Count);
}

// Return the current item.
public Object Current { get { ValidateIndex(); return items[index];
} }

// Return the current dictionary entry.
public DictionaryEntry Entry
{
get { return (DictionaryEntry)Current; }
}

// Return the key of the current item.
public Object Key { get { ValidateIndex(); return items[index].Key;
} }
// Return the value of the current item.
public Object Value { get { ValidateIndex(); return
items[index].Value; } }

// Advance to the next item.
public Boolean MoveNext()
{
if (index < items.Length - 1) { index++; return true; }
return false;
}

// Validate the enumeration index and throw an exception if the
index is out of range.
private void ValidateIndex()
{
if (index < 0 || index >= items.Length)
throw new InvalidOperationException("Enumerator is before or
after the collection.");
}

// Reset the index to restart the enumeration.
public void Reset()
{
index = -1;
}
}
public IDictionaryEnumerator GetEnumerator()
{
// Construct and return an enumerator.
return new MyClassEnumerator(this);
}
#endregion

#region ICollection Members
public bool IsSynchronized { get { return false; } }
public object SyncRoot { get { throw new NotImplementedException(); }
}
public int Count { get { return ItemsInUse; } }
public void CopyTo(Array array, int index) { throw new
NotImplementedException(); }
#endregion

#region IEnumerable Members
IEnumerator<int> IEnumerable.GetEnumerator()
{
// Construct and return an enumerator.
return ((IDictionary)this).GetEnumerator();
}
endregion
}

Rich
 
Thank you for your reply. I made a few changes (like class name to
MyClassCollection. I also applied your suggestions above. I made
everything that said key and<int> and everything that said Value
<MyClass>. I am getting 17 errors. Following are 3 of the errors (one
error is common to about 10 of the errors, the 3rd error is self
explanatory) and a relisting of my collection class with the changes
that I have made thus far (note: the whole point of this exercise is to
learn how to implement interfaces and interfaces with members):

Error 1 -- 'InterfaceDictionary.MyClassCollection' does not implement
interfacemember 'System.Collections.IEnumerable.GetEnumerator()'.
'InterfaceDictionary.MyClassCollection.GetEnumerator()' cannot implement
'System.Collections.IEnumerable.GetEnumerator()' because it does not
have the matching return type of 'System.Collections.IEnumerator'.
Error 2 -- 'InterfaceDictionary.MyClassCollection' does not implement
interface member
'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyVa
luePair<int,InterfaceDictionary.MyClass>>.GetEnumerator()'.
'InterfaceDictionary.MyClassCollection.GetEnumerator()' cannot implement
'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyVa
luePair<int,InterfaceDictionary.MyClass>>.GetEnumerator()' because it
does not have the matching return type of
'System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyVa
luePair<int,InterfaceDictionary.MyClass>>'.

Error 11 -- 'IEnumerable.GetEnumerator' in explicit interface
declaration is not a member of interface

The problem must be with those two:
public IDictionaryEnumerator GetEnumerator()
{
// Construct and return an enumerator.
return new MyClassEnumerator(this);
}
IEnumerator<int> IEnumerable.GetEnumerator()
{
// Construct and return an enumerator.
return ((IDictionary)this).GetEnumerator();
}

They seems to have wrong return types compared to
the interfaces.

The easiest would probbaly be to ask your IDE to add the
missing methods and see the proper signature.

Arne
 
The problem must be with those two:



They seems to have wrong return types compared to
the interfaces.

The easiest would probbaly be to ask your IDE to add the
missing methods and see the proper signature.

I just did. They are supposed to be:

public IEnumerator<KeyValuePair<int, MyClass>> GetEnumerator()

IEnumerator IEnumerable.GetEnumerator()

Arne
 
They seems to have wrong return types compared to
the interfaces.

The easiest would probbaly be to ask your IDE to add the
missing methods and see the proper signature.

Arne
<

I'm using VS2008 Pro. How would I go about asking the IDE to add the
missing methods? I don't mind recreating the class. It's not that big.
I started kicking around with MVC, and when you start an MVC project
(asp.net) the IDE sets up all sorts of classes and stuff by default.
Are you suggesting default stuff? I guess I should add that in addition
to learning about implementing interfaces and members, I am sure there
is still a lot I need to learn about the IDE. Any suggestions
appreciated on how to perform the operation of adding the missing
methods.

Rich
 
I'm using VS2008 Pro. How would I go about asking the IDE to add the
missing methods?

Right click and chose "implement interface - implement interface".

Edit the method bodies but keep the signatures as is.

Arne
 
Thank you very much. I had to do that same operation with the
interfaces with this sample MVC project I was practicing with. On the
exercise for this post -- this operation has now reinforced how to
implement interfaces with the right-click menu. I decided to start the
class over from scratch with just the signature and then implement the
interface from the right-click menu as you suggested. I think I can
take it from here.

Many thanks again for the help.

Rich
 
Back
Top