4

I am familiar with the fact that an interface contains only the signatures of methods, delegates or events. The implementation of the methods is done in the class that implements the interface. the class that implements the interface MUST implement its methods.

I created a generic List. when i browse into the declaration of List, i see that it inherits ICollection, and ICollection has a signature method of: object SyncRoot { get; } why don't i see the SyncRoot implementation in List class?

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>,
                       IList, ICollection, IEnumerable
{
    public List();
    public List(IEnumerable<T> collection);
    public List(int capacity);
}

I expect to see: public object syncRoot() in the above? Also, if i open it with JustDecompile (Telerik) I see that it is implemented but as private. Am i missing anything?

Yuck
  • 49,664
  • 13
  • 105
  • 135
user829174
  • 6,132
  • 24
  • 75
  • 125
  • 4
    http://stackoverflow.com/questions/143405/c-interfaces-implicit-and-explicit-implementation – dtb Jan 04 '12 at 15:59
  • Shark, what do you mean? what does 0% means? – user829174 Jan 04 '12 at 16:01
  • 3
    0% acceptance after asking 10 questions is very poor form. Please re-visit some of your previous questions and click the 'tick' next to any answers you think were suitable, well written or helpful. – ColinE Jan 04 '12 at 16:01
  • "I am familiar with the fact that an interface contains only the signatures of methods" that is incorrect. It contains declaration of methods (return type and attributes). – Lukasz Madon Jan 04 '12 at 16:07

1 Answers1

6

It is an explicit interface implementation as @dtb points out. This means that the member SyncRoot is visible if used from a reference of type ICollection but not from a references of type List

var l = new List<int>();

// compiler error
var sr1 = l.SyncRoot;

ICollection c = l;

// works
var sr2 = c.SyncRoot;

This is the power of explicit interface implementation. If, for some reason, you wanted to define a base behavior for an interface reference, but specialized behavior for your class reference (like changing a return type to be more specific, which typically isn't valid in a plain overload) you can do this. Or, if you want to implement an interface for legacy purposes, but want to hide a method or property that is no longer useful in your implementation.

Thus, if you look at the decompiled code, you'll see a declaration like:

object ICollection.SyncRoot
{
    ...
}

So this implements SyncRoot for the ICollection interface, making it visible through any ICollection reference to a List<T> object, but hides it for any other (non-ICollection) reference to a List<T> object.

This is also very useful when working with legacy interfaces like IEnumerable. For example, if you want to support IEnumerable<T> you must also support IEnumerable, but they both have GetEnumerator() methods that differ by return type. For example:

public class MySpecialList<T> : IEnumerable<T>
{
    // if we access from any other reference, we get the new, generic
    // interface
    public IEnumerator<T> GetEnumerator()
    {
        // your actual implementation
    }

    // so if we access from a reference of IEnumerable, we get older,
    // non-generic interface
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Because we can't have two methods (overloads) that return different values but have same signature, we can tell the class that GetEnumerator() means one thing when used with the IEnumerable legacy references, and something totally different (and better) for all other references:

var x = new MySpecialList<int>();
IEnumerable y = x;

// returns the generic enumerator
var genericEnum = x.GetEnumerator();  

// since called from an IEnumerable, gets legacy enumerator
var legacyEnum = y.GetEnumerator(); 
James Michael Hare
  • 37,767
  • 9
  • 73
  • 83
  • this i know, my question is why don't i see the implementation of it in List. after all, List inherits from ICollection and i should see it in class List (F12), no? – user829174 Jan 04 '12 at 16:04
  • 1
    @user829174: because it's private. It is only visible through an `ICollection` reference – James Michael Hare Jan 04 '12 at 16:05
  • @user829174 where are you looking ? – nos Jan 04 '12 at 16:06
  • @user829174, you missed the point of explicit interface implementation. Through an explicit implementation, you *don't* see the method or property as part of the public API of the class. You *only* see it via the interface reference, as James has demonstrated. – Anthony Pegram Jan 04 '12 at 16:07
  • i Created: List d = new List {6, 7}; then i press F12 (Go to definition). I can see public class List : IList, ..... ICollection here i expect to see 'public Object SyncRoot()' implementation – user829174 Jan 04 '12 at 16:08
  • @user829174, you're looking at basically the public API generated from metadata, you're not seeing implementation details. `SyncRoot` is not part of the public API of the class! – Anthony Pegram Jan 04 '12 at 16:12
  • @user829174: Exactly, the explicit interface implementation is private and hidden to all references to the class EXCEPT references of `ICollection` (in this case). – James Michael Hare Jan 04 '12 at 16:12
  • But interfaces are implicitly Public (and abstract) how come you can implement it with Private modifier? – user829174 Jan 04 '12 at 16:16
  • @user829174: Because it is an explicit interface implementation. You are satisfying the interface EXPLICITLY by telling it what to do for that interface, but doing so makes it private for all other references. This is how they work and how they give us power to override or hide interface behaviors that may no longer be desirable, yet still makes them available if accessed through legacy interfaces. – James Michael Hare Jan 04 '12 at 16:20
  • @user829174: And yes, the keyword there is implicitly. When you implicitly implement an interface, it is `public` as well. Only explicit implementation allows it to be private because you are giving it a very specialized behavior for the interface references alone. – James Michael Hare Jan 04 '12 at 16:21
  • @user829174, you actually wouldn't use the `private` modifier (or *any* access modifier) on the explicit implementation, it wouldn't compile. If you're seeing that via the decompiler, it's doing that in error. – Anthony Pegram Jan 04 '12 at 16:32
  • @AnthonyPegram: True, it's more *implicitly* private to those outside of the explicit interface of the method being implemented. – James Michael Hare Jan 04 '12 at 16:35