2009-04-27 8 views
21

J'ai ce code C#:mise en œuvre abstraite d'interface explicite en C#

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

    //abstract IEnumerator IEnumerable.GetEnumerator(); 
} 

Comme il est, je reçois:

'Type' ne met pas en oeuvre un membre d'interface « System.Collections.IEnumerable.GetEnumerator() '.

supprimer le commentaire et je reçois:

Le modificateur 'abstrait' est pas valable pour cet article

Comment puis-je faire une implémentation explicite abstraite

+0

Cette est une lacune du compilateur C# IMHO. Il existe de nombreux cas d'utilisation où vous devrez ajouter une implémentation fictive "juste parce que". De plus, si vous choisissez d'avoir un membre non abstrait, le compilateur autorisera les sous-classes sans implémentation, exposant le risque d'appel de l'implémentation fictive. –

Répondre

29

Intéressant - Je ne suis pas sûr que tu puisses. Cependant, si c'est votre vrai code, voulez-vous jamais implémenter le GetEnumerator() non-générique d'une manière ou d'une autre en appelant le générique?

Je ferais ceci:

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

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

qui vous sauve de l'ennui d'avoir à mettre en œuvre dans chaque classe dérivée - qui sans doute utiliser toute la même mise en œuvre.

+2

Je n'ai aucune raison de penser qu'il sera mis en œuvre d'une autre manière ... mais on ne sait jamais. +1 – BCS

+2

Re votre commentaire - Je l'ai peut-être mal lu ...édité pour le réparer, et trouvé le code identique au vôtre - donc j'ai supprimé ;-p –

14

Même si un membre d'interface explicite ne peut pas être abstraite (ou virtuelle), il peut être mis en œuvre en termes d'un résumé (ou virtuel) membre 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" 
} 

que j'ai trouvé le besoin de cela dans vues partielles ASP.NET MVC 3 fortement typées, qui ne prennent pas en charge les modèles de définition de type générique (pour autant que je sache).

+0

Je me suis retrouvé devant utiliser cette solution aussi. Merci! (La réponse de Jon Skeets est logique dans l'exemple fourni, mais s'il n'y a pas de relation aussi simple, cela semble être la solution la plus saine pour autant que je sache.) – AnorZaken

0

J'ai eu un cas légèrement plus compliqué où je voulais qu'une classe de base implémente explicitement l'interface non générique et qu'une classe dérivée implémente l'interface générique.

Interfaces:

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

public interface IIdentifiable 
{ 
    object Id { get; } 
} 

Je l'ai résolu en déclarant une méthode abstraite getter dans la classe de base et de laisser la mise en œuvre explicite appeler:

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

Notez que la classe de base n'a pas la version dactylographiée de Id il pourrait appeler.

1

Vous pouvez réellement le faire, en forçant une classe qui dérive d'une classe abstraite, pour implémenter une interface et permet encore de choisir comment implémenter cette interface - implicitement ou explicitement:

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