在C#中,抽象显式接口实现

33

我有这段 C# 代码:

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

    //abstract IEnumerator IEnumerable.GetEnumerator();
}

目前的情况是:

'Type'未实现接口成员'System.Collections.IEnumerable.GetEnumerator()'

如果去掉注释,则会得到以下错误:

修饰符“abstract”对此项无效

如何将显式实现变为抽象实现?


2
在我看来,这是C#编译器的一个缺陷。有许多情况下,你必须添加一个虚拟实现“只是因为”。此外,如果你选择将成员设置为非抽象的,编译器将允许没有实现的子类存在,从而暴露调用虚拟实现的风险。 - Jack Wester
5个回答

37

有趣 - 我不确定你能否实现。然而,如果这是你的真实代码,你是否想以任何方式实现非泛型的GetEnumerator(),而不是调用泛型版本?

我会这样做:

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

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

这样可以避免你在每个派生类中都实现相同的代码,免去了繁琐的工作。


2
我没有理由认为它会以其他方式被实现...但你永远不知道。+1 - BCS
2
关于您的评论 - 我可能误读了它...已经进行修正,发现代码与您的完全相同 - 因此已删除 ;-p - Marc Gravell

23

尽管显式接口成员可能不是抽象的(或虚拟的),但它可以通过抽象的(或虚拟的)成员来实现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
我也发现自己不得不使用这个解决方案。谢谢!(Jon Skeets的答案在提供的示例中是有道理的,但如果没有这样简单的关系,据我所知,这似乎是最明智的解决方案。) - AnorZaken
谢谢。这样你也可以实现一种内部接口方法。如果接口是内部的,抽象方法也是内部的。 - Robert S.

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

这是一个“越来越好奇”的模式。现在你可以添加:public class Sample2 : BaseClass<Sample>, IBase<Sample2>,它并不像你期望的那样工作。它基本上声明了Base<T>,其中T:Base<T>可以是任何Base<T>。例如,X:Base<X>和Y:Base<X>。 - Wouter

0

我有一个稍微复杂一些的情况,我希望基类显式地实现非泛型接口,而派生类实现泛型接口。

接口:

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

public interface IIdentifiable
{
    object Id { get; }
}

我通过在基类中声明一个抽象的getter方法并让显式实现调用它来解决了这个问题:
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

0

看起来无法进行抽象显式接口实现,但是你可以通过一种变通方法来摆脱错误,同时仍然强制使用隐式接口实现:

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

然而,正如上面问题的评论所指出的那样:

如果您选择将成员设置为非抽象的,则编译器将允许子类没有(自己的)实现...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接