I'm new to C#, so just point me at the correct reference material if this
question has been answered before.
When creating a new class which implements the IDictionary interface, two
versions of the GetEnumerator method must be defined (one from the
IDictionary interface, one from the IEnumerable interface).
The first is defined as:
public IDictionaryEnumerator GetEnumerator()
and the second is defined as:
IEnumerator System.Collections.IEnumerable.GetEnumerator()
Several questions arise in my mind:
1) Why are 2 methods needed? Since IDictionaryEnumerator EXTENDS
IEnumerator, doesn't the 1st method above also satisfy the interface
requirement for IEnumerable? (If the 2nd method is dropped, you get a compile
error).
2) Why can't the 2nd method be made 'public'? (Another compile error.)
3) If you write an instance method of the form:
public void TestMethod()
{
object obj = GetEnumerator();
}
the 1st method is invoked. Shouldn't this be an ambiguous call and
generate a comile error? How is the first method selected?
4) If you wanted to call the 2nd method from within TestMethod(), what would
be the syntax? I tried a couple of ways, and always got a compile error.
Source for a full test case is patched in below.
Thanks for any help on this puzzle.
John
===================== Test Case Console App ===================
using System;
using System.Collections;
namespace ConsoleApplication1
{
//
// This is a test case for a language issue that I'm trying to resolve.
//
// The TestIDictionary class is defined below -- it implements the
IDictionary interface.
//
// All of the code in TestIDictionary is GENERATED by Visual Studio (by a
TAB after
// typing the : IDictionary entry) with the exception of the
System.Console.... lines
// and the CallGetEnumerator() method.
//
// There are several questions which I am trying to resolve:
//
// 1) Why are there TWO GetEnumerator() methods?
//
// The generated code has the methods:
//
// public IDictionaryEnumerator GetEnumerator()
// AND IEnumerator
System.Collections.IEnumerable.GetEnumerator()
//
// but since IDictionaryEnumerator EXTENDS IEnumerator, shouldn't the
// first of the methods above ALSO satisfy the requirements of the
// IEnumerable interface (i.e. a GetEnumerator() method which
returns an
// IEnumerator)?
//
// I.e. Why isn't only the 1st method required?
//
// And it is required, because if you drop the 2nd method you get a
compile
// error. (You also get an error if you make the 2nd method
'public'! Why???)
//
// 2) Aren't the calls on GetEnumerator() ambiguous?
//
// There are 2 GetEnumerator() methods. When called as an instance
method
// (e.g. the tst.GetEnumerator() call below) I can see that the
//
// public IDictionaryEnumerator GetEnumerator()
//
// method is called since it is 'public' and the other one is not.
//
// But within the method CallGetEnumerator() BOTH methods are
visible.
// Why isn't this a compile-time error (ambiguity)???
//
// And why is the compiler selecting the 1st method instead of the
2nd?
// Is it the order of appearance in the text? Level of
accessibility?
//
// 3) What is the syntax used to actually invoke the 2nd method?
//
// If you insert into CallGetEnumerator the line:
//
// System.Collections.IEnumerable.GetEnumerator()
//
// you get the error:
//
// An object reference is required for the non-static field,
method, or property 'System.Collections.IEnumerable.GetEnumerator()'
//
// Why should this be an error since the call is made from within
an instance
// method -- so 'this' should be assumed?
//
// Likewise, inserting the line:
//
// this.System.Collections.IEnumerable.GetEnumerator( )
//
// leads to another error ('System' is not a defined variable,
method, or property).
//
//
class Class1
{
[STAThread]
static void Main(string[] args)
{
System.Console.WriteLine("Starting Test");
TestIDictionary tst = new TestIDictionary();
System.Console.WriteLine("Calling GetEnumerator on an instance");
tst.GetEnumerator();
System.Console.WriteLine("Calling GetEnumerator thru a Method of
the Class");
tst.CallGetEnumerator();
System.Console.WriteLine("End Test");
}
}
//
// This is the Test class with stub implementation as generated
// NOTE: The only changes are in the 2 GetEnumerator() methods
// and adding the CallGetEnumerator() method.
//
public class TestIDictionary: IDictionary
{
#region IDictionary Members
public bool IsReadOnly
{
get
{
// TODO: Add TestIDictionary.IsReadOnly getter implementation
return false;
}
}
public IDictionaryEnumerator GetEnumerator()
{
// FOLLOWING LINE ADDED TO THE GENERATED STUB CODE
System.Console.WriteLine("IDictionaryEnumerator GetEnumerator()
was called");
// TODO: Add TestIDictionary.GetEnumerator implementation
return null;
}
public object this[object key]
{
get
{
// TODO: Add TestIDictionary.this getter implementation
return null;
}
set
{
// TODO: Add TestIDictionary.this setter implementation
}
}
public void Remove(object key)
{
// TODO: Add TestIDictionary.Remove implementation
}
public bool Contains(object key)
{
// TODO: Add TestIDictionary.Contains implementation
return false;
}
public void Clear()
{
// TODO: Add TestIDictionary.Clear implementation
}
public ICollection Values
{
get
{
// TODO: Add TestIDictionary.Values getter implementation
return null;
}
}
public void Add(object key, object value)
{
// TODO: Add TestIDictionary.Add implementation
}
public ICollection Keys
{
get
{
// TODO: Add TestIDictionary.Keys getter implementation
return null;
}
}
public bool IsFixedSize
{
get
{
// TODO: Add TestIDictionary.IsFixedSize getter
implementation
return false;
}
}
#endregion
#region ICollection Members
public bool IsSynchronized
{
get
{
// TODO: Add TestIDictionary.IsSynchronized getter
implementation
return false;
}
}
public int Count
{
get
{
// TODO: Add TestIDictionary.Count getter implementation
return 0;
}
}
public void CopyTo(Array array, int index)
{
// TODO: Add TestIDictionary.CopyTo implementation
}
public object SyncRoot
{
get
{
// TODO: Add TestIDictionary.SyncRoot getter implementation
return null;
}
}
#endregion
#region IEnumerable Members
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
// FOLLOWING LINE ADDED TO THE GENERATED STUB CODE
System.Console.WriteLine("System.Collections.IEnum erable
GetEnumerator() was called");
// TODO: Add
TestIDictionary.System.Collections.IEnumerable.Get Enumerator implementation
return null;
}
#endregion
//
// Test code to determine which GetEnumerator() is invoked!
//
public void CallGetEnumerator()
{
GetEnumerator(); // WHY ISN'T THIS CALL AMBIGUOUS?
// System.Collections.IEnumerable.GetEnumerator(); // ERROR
}
}
}