简体   繁体   中英

abstract explicit interface implementation in C#

I have this C# code:

abstract class MyList : IEnumerable<T>
{
    public abstract IEnumerator<T> GetEnumerator();

    //abstract IEnumerator IEnumerable.GetEnumerator();
}

As is, I get:

'Type' does not implement interface member 'System.Collections.IEnumerable.GetEnumerator()'.

remove the comment and I get:

The modifier 'abstract' is not valid for this item

How do I make an explicit implementation abstract

Interesting - I'm not sure you can. However, if this is your real code, do you ever want to implement the non-generic GetEnumerator() in any way other than by calling the generic one?

I'd do this:

abstract class MyList<T> : IEnumerable<T>
{
    public abstract IEnumerator<T> GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() 
    {
        return GetEnumerator();
    }
}

That saves you from the tedium of having to implement it in every derived class - which would no doubt all use the same implementation.

While an explicit interface member may not be abstract (or virtual), it may be implemented in terms of an abstract (or virtual) member 1 :

public abstract class Foo: IEnumerable {
    IEnumerator IEnumerable.GetEnumerator() { 
        return getEnumerator();    
    }

    protected abstract IEnumerator getEnumerator(); 
}

public class Foo<T>: Foo, IEnumerable<T> {
    private IEnumerable<T> ie;
    public Foo(IEnumerable<T> ie) {
        this.ie = ie;
    }

    public IEnumerator<T> GetEnumerator() {
        return ie.GetEnumerator();
    }

    protected override IEnumerator getEnumerator() {
        return GetEnumerator();
    }

    //explicit IEnumerable.GetEnumerator() is "inherited"
}

I've found the need for this in strongly typed ASP.NET MVC 3 partial views, which do not support generic type definition models (as far as I know).

You actually can do it, by forcing a class, which derives from an abstract class, to implement an interface, and still allow it to choose how to implement that interface - implicitly or explicitly:

namespace Test
{
    public interface IBase<T>
    {
        void Foo();
    }

    public abstract class BaseClass<T> 
        where T : IBase<T>  // Forcing T to derive from IBase<T>
    { }

    public class Sample : BaseClass<Sample>, IBase<Sample>
    {
        void IBase<Sample>.Foo() { }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Sample sample = new Sample();

            // Error CS1061  'Sample' does not contain a definition for 'Foo' 
            // and no extension method 'Foo' accepting a first argument of type 'Sample' 
            // could be found(are you missing a using directive or an assembly reference ?)
            sample.Foo();

            (sample as IBase<Sample>).Foo(); // No Error
        }
    }
}

I had a slightly more complicated case where I wanted a base class to implement the non generic interface explicitly and a derived class implement the generic interface.

Interfaces:

public interface IIdentifiable<TKey> : IIdentifiable
{
    TKey Id { get; }
}

public interface IIdentifiable
{
    object Id { get; }
}

I solved it by declaring an abstract getter method in the base class and letting the explicit implementation call it:

public abstract class ModelBase : IIdentifiable
{
    object IIdentifiable.Id
    {
        get { return GetId();  }
    }

    protected abstract object GetId();
}

public class Product : ModelBase, IIdentifiable<int>
{
    public int ProductID { get; set; }

    public int Id
    {
        get { return ProductID; }
    }

    protected override object GetId()
    {
        return Id;
    }
}

Note that the base class does not have the typed version of Id it could call.

It seems not possible to do an abstract explicit interface implementation, but you can do a workaround to get rid of the error, but still force to use the explicit interface implementation by the implicit one:

abstract class MyList : IEnumerable<T>
{
    public virtual IEnumerator<T> GetEnumerator() {
        (this as IEnumerable).GetEnumerator();
    }
}

However, as pointed out by a comment on the question above:

If you chose to have the member non abstract, the compiler will allow subclasses without (an own) implementation...

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