2009-04-27 5 views
21

У меня есть этот C# код:абстрактный реализация явного интерфейса в C#

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

    //abstract IEnumerator IEnumerable.GetEnumerator(); 
} 

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

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

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

Модификатор «абстрактное» не является допустимым для данного элемента

Как сделать Явное абстрактном реализация

+0

Этот является недостатком компилятора C# IMHO. Существует много вариантов использования, когда вам нужно будет добавить фиктивную реализацию «только потому, что». Кроме того, если вы решили, что член не абстрактный, компилятор разрешит подклассы без реализации, подвергая риску вызов фиктивной реализации. –

ответ

29

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

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

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

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

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

+2

У меня нет причин думать, что это будет реализовано любым другим способом ... но вы никогда не знаете. +1 – BCS

+2

Ваш комментарий - Возможно, я неправильно понял ...отредактированный, чтобы исправить его, и нашел код, идентичный вашему - так что удалил ;-p –

14

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

+0

Мне тоже пришлось использовать это решение. Благодаря! (Ответ Jon Skeets имеет смысл в приведенном примере, но если нет такого простого отношения, это, по-моему, самое надежное решение, насколько мне известно). – AnorZaken

0

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

Интерфейсы:

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, которую он мог вызвать.

1

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

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 
     } 
    } 
} 
Смежные вопросы