Let\'s take the interface IQueryable
for example:
public interface IQueryable : IQueryable, IEnumerable;
Sin
This is not true. I suspect you are right-clicking on these classes/interfaces in Visual Studio and clicking on "Go to definition," and this is what the metadata is telling you. If you want to really understand what's happening, here's an example:
public interface IAddTwo
{
int AddTwo(int x);
}
public interface IAddTwoOrThree : IAddTwo
{
int AddThree(int y);
}
public class AddTwoOrThree : IAddTwoOrThree
{
public int AddTwo(int q)
{
return q + 2;
}
public int AddThree(int z)
{
return z + 3;
}
}
Note that the last class only has to implement one interface (but that you get a compiler error if you leave off either method.
Create the above as a class library, add a reference by BROWSING to the resulting DLL (not by adding a reference to the project), and view the metadata for AddTwoOrThree. You will see
AddTwoOrThree : IAddTwoOrThree, IAddTwo
Viola! This is why you see what you are seeing on MSDN. They show the metadata, not the way their coders wrote the code.
Mentioning the grandparent (and higher ancestors) in the declaration is not strictly necessary, but since the parent, being an interface, didn't actually implement the grandparent, its better to mention the grandparent in the declaration of the grandchild to improve documentation for the eventual implementer.
Thats why, in case of concrete implementations in the ancestry , you see the following in MSDN:
public class Button : ButtonBase,IButtonControl
and not the following ...
public class Button : ButtonBase,Control,Component,MarshalByRefObject,Object
Its because Interface inheritance is a pure language sugar thing. When compiling to IL, the interface explicitly implements all the interfaces in the chain so looking at the signature for IQueryable<T>
will end up looking like
.class public interface abstract auto ansi IQueryable<+ T>
implements [mscorlib]System.Collections.Generic.IEnumerable`1<!T>, System.Linq.IQueryable, [mscorlib]System.Collections.IEnumerable
{
}
And since most documentation is auto generated from metadata, and not the original sourcecode, it will end up showing the signature as its implementing all the interfaces directly, and not via inheritance. Which is basically how it is. The only reason YOU can take advantage of inheritance is because the compiler will end up creating the right signature for you, wiring up all the interfaces explicitly.
The correct definition is:
public interface IQueryable<out T> : IEnumerable<T>, IQueryable { }
The following was taken from Microsoft's Source RTMRel\ndp\fx\src\Core\System\Linq\IQueryable.cs\1305376\IQueryable.cs
public interface IQueryable : IEnumerable {
Expression Expression { get; }
Type ElementType { get; }
// the provider that created this query
IQueryProvider Provider { get; }
}
#if SILVERLIGHT
public interface IQueryable<T> : IEnumerable<T>, IQueryable {
#else
public interface IQueryable<out T> : IEnumerable<T>, IQueryable {
#endif
}
public interface IQueryProvider{
IQueryable CreateQuery(Expression expression);
IQueryable<TElement> CreateQuery<TElement>(Expression expression);
object Execute(Expression expression);
TResult Execute<TResult>(Expression expression);
}
public interface IOrderedQueryable : IQueryable {
}
#if SILVERLIGHT
public interface IOrderedQueryable<T> : IQueryable<T>, IOrderedQueryable {
#else
public interface IOrderedQueryable<out T> : IQueryable<T>, IOrderedQueryable {
#endif
}