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();