Search code examples
c#interfaceienumerableimplementationienumerator

Difference between implicit and explicit implementation of GetEnumerator() from IEnumerable


I have this class but I can't understand why it is useful to have one implementation as: public IEnumerator GetEnumerator() and the other as: IEnumerator IEnumerable.GetEnumerator(). I know that to use the second I must access it as an instance of the interface itself and not as an instance of the class since this member would not be visible but I cannot understand the difference and usefulness of these techniques.

internal class CoffeeCollection : IEnumerable
{

    private CoffeeEnumerator enumerator;

    public CoffeeCollection()
    {
        enumerator = new CoffeeEnumerator();
    }

    public IEnumerator GetEnumerator()
    {
        return enumerator;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        Form1.labelExplicitImplementation.Visible = true;
        return enumerator;
    }
}

I was trying to understand the difference between both implementations but I couldn't.


Solution

  • An explicit interface implementation can be useful when you want to restrict usage somehow. Or possibly if you want implementations to be different somehow, but you probably want to limit any differences since it could make the code more difficult to reason about.

    In your specific example there is no point in providing both en implicit and explicit interface implementation since there is no real difference between them. But consider the following example:

    public interface IMyObject{}
    public class MyObject : IMyObject{}
    
    public interface IMyService
    {
        IMyObject Object { get; }
    }
    public class MyService : IMyService
    {
        public MyObject Object { get; set; } = new MyObject();
        IMyObject IMyService.Object  => this.Object;
    }
    

    If you have a IMyService-reference you can only get the interface to the object. But if you have a MyService-reference you get access to the underlying type, and can also change the object. So this can allow you to get some level of separation and isolation between components depending on their need.

    A real world example would be the Progress<T>-class that implements IProgress<T>. Where the API of the base class and the interface have no overlap at all. Since the one that creates the progress object need to register event handlers etc, but does not need to report progress, and the methods using the interface should only report progress.

    You could of course side step such "protections" by type checking, but if you find yourself doing that you should probably think a bit more if you are doing the right thing.