简体   繁体   中英

A question about interface inheritance in .NET

Let's take the interface IQueryable<T> for example:

public interface IQueryable<T> : IQueryable, IEnumerable;

Since IQueryable in turn implements IEnumerable:

public interface IQueryable : IEnumerable;

why in the first declaration, IQueryable has to explicitly implement IEnumerable as well? This is different from class inheritance where you do not have to explicitly inherit from a "grandparent"?

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

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.

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 
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM