0

I am trying to understand how C# implements the Dictionary. It seems to me that Dictionary is supposed to inherit from IEnumerable which requires the method implementation for:

IEnumerable GetEnumerator()

However, the C# Dictionary instead implements:

Dictionary<T>.Enumerator GetEnumerator()

Where Enumerator is a nested struct which inherits from IEnumerator.

I have created an example of this relationship:

public interface IFoo
{
    IFoo GetFoo();
}

public abstract class Foo : IFoo
{
    public abstract FooInternal GetFoo();

    public struct FooInternal : IFoo
    {
        public IFoo GetFoo()
        {
            return null;
        }
    }
}

However, this doesn't compile, resulting in the following error:

Error   2   'Foo' does not implement interface member 'IFoo.GetFoo()'. 'Foo.GetFoo()' cannot implement 'IFoo.GetFoo()' because it does not have the matching return type of 'CodeGenerator.UnitTests.IFoo'. Foo.cs  14

Any thoughts on what I might be doing wrong here? How does C# implement the Dictionary? How would one make the example code compile similarly to the C# Dictionary?

4

2 回答 2

3

You are missing an explicit interface implementation:

public abstract class Foo : IFoo
{
    public abstract FooInternal GetFoo();

    // start here
    IFoo IFoo.GetFoo()
    {
        return GetFoo();
    }
    // end here

    public struct FooInternal : IFoo
    {
        public IFoo GetFoo()
        {
            return null;
        }
    }
}
于 2013-05-17T03:44:02.173 回答
1

You are confusing two distinct interfaces, namely IEnumerable and IEnumerator.

The outer class, the dictionary class, implements IEnumerable. This involves that the outer class has a method GetEnumerator. This method returns an instance of the nested (inner) struct.

The inner struct implements IEnumerator. To implement IEnumerator you must have a MoveNext method and a Current property.

Besides, there's the issue of explicit interface implementation which is mentioned also by Andrey Shchekin's answer. This code is legal and similar to Dictionary<,>:

public interface IFoo   // corresponds to IEnumerable
{
  IBar GetBar();
}

public interface IBar   // corresponds to IEnumerator
{
}


public class Foo : IFoo
{
  // public method that has BarInternal as return type
  public BarInternal GetBar()
  {
    return new BarInternal();
  }

  // explicit interface implementation which calls the public method above
  IBar IFoo.GetBar()
  {
    return GetBar();
  }

  public struct BarInternal : IBar
  {
  }
}

It would also be possible to implement the IFoo "directly" (not explicitly) by a public method, but then the declared return type must match:

public class Foo : IFoo
{
  // public method that directly implements the interface
  public IBar GetBar()
  {
    return new BarInternal();
  }

  public struct BarInternal : IBar
  {
  }
}

The reason why Dictionary<,> isn't written in this simpler way, is that you get boxing of the nested struct, I guess.

Note that when you foreach through a Dictionary<,>, the C# compiler first searches for a public non-generic parameterless instance method with the exact name GetEnumerator. If such a method is found, it is used, and the compiler doesn't care about IEnumerable. Therefore, with a Dictionary<,>, the slightly more optimal public method which does not implement the interface, is used during foreach.

Explicit interface implementations are documented on MSDN. See Dictionary<TKey, TValue>.IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator (generic) and Dictionary<TKey, TValue>.IEnumerable.GetEnumerator (non-generic).

于 2013-05-17T08:28:32.177 回答