implementación de interfaz explícita en C#


Tengo este código C#:

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

    //abstract IEnumerator IEnumerable.GetEnumerator();
}

Tal como está, obtengo:

'Type' no implementa el sistema de miembro de interfaz.Colecciones.IEnumerable.GetEnumerator()'.

Elimina el comentario y obtengo:

El modificador 'abstract' no es válido para este ítem

¿Cómo hago una implementación explícita abstract

Author: Marc Gravell, 2009-04-28

4 answers

Interesante - No estoy seguro de que puedas. Sin embargo, si este es su código real, ¿alguna vez desea implementar el no genérico GetEnumerator() de alguna manera otro que llamando al genérico?

Yo haría esto:

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

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

Eso le ahorra el tedio de tener que implementarlo en cada clase derivada, que sin duda todas usarían la misma implementación.

 31
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-27 20:21:51

Si bien un miembro explícito de la interfaz puede no ser abstracto (o virtual), puede implementarse en términos de un miembro abstracto (o virtual) 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"
}

He encontrado la necesidad de esto en fuertemente mecanografiado ASP.NET MVC 3 vistas parciales, que no admiten modelos de definición de tipo genérico (que yo sepa).

 15
Author: Stephen Swensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-31 14:14:04

En realidad se puede hacerlo, forzando a una clase, que deriva de una clase abstracta, a implementar una interfaz, y aún así permitirle elegir cómo implementar esa interfaz - implícita o explícitamente:

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
        }
    }
}
 1
Author: Yekke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-30 16:38:56

Tuve un caso un poco más complicado donde quería una clase base para implementar la interfaz no genérica explícitamente y una clase derivada implementar la interfaz genérica.

Interfaces:

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

public interface IIdentifiable
{
    object Id { get; }
}

Lo resolví declarando un método getter abstracto en la clase base y dejando que la implementación explícita lo llamara:

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

Tenga en cuenta que la clase base no tiene la versión escrita de Id que podría llamar.

 0
Author: Olivier Jacot-Descombes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-17 17:47:43