абстрактная явная реализация интерфейса в C # - PullRequest
25 голосов
/ 28 апреля 2009

У меня есть этот код C #:

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

    //abstract IEnumerator IEnumerable.GetEnumerator();
}

Как есть, я получаю:

«Тип» не реализует элемент интерфейса «System.Collections.IEnumerable.GetEnumerator ()».

удалите комментарий, и я получу:

Модификатор 'abstract' недействителен для этого элемента

Как сделать абстрактную реализацию явной

Ответы [ 5 ]

33 голосов
/ 28 апреля 2009

Интересно - я не уверен, что вы можете. Однако, если это ваш реальный код, хотите ли вы когда-нибудь реализовать неуниверсальный GetEnumerator() каким-либо образом , чем , кроме как с помощью вызова универсального?

Я бы сделал это:

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

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

Это избавляет вас от утомительной необходимости реализовывать его в каждом производном классе - который, несомненно, будет использовать одну и ту же реализацию.

16 голосов
/ 30 мая 2011

Хотя явный элемент интерфейса не может быть абстрактным (или виртуальным), он может быть реализован в виде абстрактного (или виртуального) члена 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"
}

Я нашел необходимость в этом в строго типизированных частичных представлениях ASP.NET MVC 3, которые не поддерживают модели определения универсального типа (насколько я знаю).

1 голос
/ 30 мая 2017

На самом деле вы можете сделать это, заставив класс, производный от абстрактного класса, реализовать интерфейс и все же позволить ему выбирать, как реализовать этот интерфейс - неявно или явно:

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
        }
    }
}
0 голосов
/ 18 февраля 2019

Кажется невозможным сделать абстрактную явную реализацию интерфейса, но вы можете сделать обходной путь, чтобы избавиться от ошибки, но все же заставить неявную реализацию явного интерфейса:

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

Однако, как указано в комментарии к вопросу выше:

Если вы выбрали неабстрактный член, компилятор разрешит подклассы без (собственной) реализации ...

0 голосов
/ 17 ноября 2015

У меня был немного более сложный случай, когда я хотел, чтобы базовый класс явно реализовывал неуниверсальный интерфейс, а производный класс реализовывал универсальный интерфейс.

Интерфейсы:

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

public interface IIdentifiable
{
    object Id { get; }
}

Я решил это, объявив абстрактный метод получения в базовом классе и позволив явной реализации вызвать его:

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;
    }
}

Обратите внимание, что базовый класс не имеет типизированной версии Id, которую он может вызвать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...