2009-04-27 15 views
21

ho questo codice C#:astratto implementazione dell'interfaccia esplicita in C#

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

    //abstract IEnumerator IEnumerable.GetEnumerator(); 
} 

Come è, ottengo:

'Tipo' non implementa il membro di interfaccia 'System.Collections.IEnumerable.GetEnumerator()'.

rimuovere il commento e ottengo:

Il modificatore 'astratta' non è valido per questo articolo

Come faccio a fare un'implementazione astratta esplicita

+0

Questo è un difetto il compilatore C# IMHO. Ci sono molti casi d'uso in cui dovrai aggiungere un'implementazione fittizia "solo perché". Inoltre, se si sceglie di rendere il membro non astratto, il compilatore consentirà le sottoclassi senza implementazione, esponendo il rischio di chiamare l'implementazione fittizia. –

risposta

29

Interessante - Non sono sicuro che tu possa Tuttavia, se questo è il tuo vero codice, desideri implementare lo GetEnumerator() non generico in qualsiasi modo altro piuttosto che chiamare quello generico?

farei questo:

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

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

che ti salva dalla noia di dover implementare in ogni classe derivata - che senza dubbio tutto utilizzare la stessa applicazione.

+2

Non ho motivo per cui penserò che verrà implementato in un altro modo ... ma non si sa mai. +1 – BCS

+2

Re il tuo commento - Potrei averlo letto male ...modificato per risolverlo, e ho trovato il codice identico al tuo - così ho cancellato ;-p –

14

Mentre un membro di interfaccia esplicito potrebbe non essere astratto (o virtuale), esso può essere implementato in termini di un abstract (o virtuale) membro 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" 
} 

ho trovato la necessità di questo in Viste parziali ASP.NET MVC 3 fortemente tipizzate, che non supportano modelli di definizione di tipi generici (per quanto ne so).

+0

Mi sono ritrovato a dover usare anche questa soluzione. Grazie! (la risposta di Jon Skeets ha senso nell'esempio fornito, ma se non esiste una relazione così semplice questa sembra essere la soluzione più sicura per quanto ne so.) – AnorZaken

0

Avevo un caso leggermente più complicato in cui volevo che una classe base implementasse esplicitamente l'interfaccia non generica e una classe derivata implementasse l'interfaccia generica.

Interfacce:

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

public interface IIdentifiable 
{ 
    object Id { get; } 
} 

ho risolto dichiarando un metodo getter astratto nella classe base e lasciando l'implementazione esplicita chiamarlo:

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

Si noti che la classe di base non ha la versione digitata di Id che potrebbe chiamare.

1

Si può effettivamente farlo, forzando una classe, che deriva da una classe astratta, per implementare un'interfaccia, e ancora permettono di scegliere come implementare tale interfaccia - implicitamente o esplicitamente:

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 
     } 
    } 
} 
Problemi correlati