内部基类的接口继承

7
我想知道是否有一种方法可以实现以下内容:
在我的项目中,我定义了一个接口,假设叫做IFruit。这个接口有一个公共方法GetName()。我还声明了一个接口IApple,它实现了IFruit并暴露了一些其他方法,比如GetAppleType()或其他什么方法。还有更多的水果,比如IBanana、ICherry等。
现在,在外部,我只想使用实际的水果实现,而不是IFruit本身。但我不能将IFruit接口声明为私有或内部,因为继承的接口会说“无法实现,因为基类不可访问”。
我知道这可以通过抽象实现来实现,但在这种情况下不是选项:我真的需要使用接口。有这样的选项吗?
更新 我想我的例子需要一些澄清 :) 我使用MEF加载接口实现。加载的集合基于IApple、IBanana、ICherry等。但IFruit本身是无用的,我不能使用仅基于该接口的类。所以我正在寻找一种方法防止其他开发人员仅实现IFruit,认为他们的类将被加载(实际上不会)。所以基本上,它归结为:


internal interface IFruit
{
  public string GetName();
}

公共接口IApple : IFruit { public decimal GetDiameter(); }

公共接口IBanana : IFruit { public decimal GetLenght(); }

但由于基础接口不可访问,这段代码无法编译。


如果你不想使用接口,那么它存在的意义是什么? - leppie
每个水果接口都将共享一组它们都需要拥有的公共方法。在我的项目内部,我使用了这个接口。我只希望外部世界无法实现它。该解决方案的某些部分是使用MEF加载的。而指定公共方法的“基础接口”并不是实际加载的接口类型。因此,当其他程序员错误地实现IFruit时,他的工作将不会被加载。我想防止这种错误。 - Jasper
如果你真的想这样做,那么在我看来,你需要使用包装器...只公开那些应该公开的内容,然后在内部使用时,用实现内部接口的内部包装器进行封装。 (是的,这意味着您必须为每种特定的水果添加 GetName(); 并为每个水果都有一个单独的包装器...但这将是从外部 API 视角下唯一干净的方式...)。 - AnorZaken
3个回答

6

为了确保不会意外发生这种情况,您可以通过将IFruit设置为程序集的internal,然后使用适当的适配器来包装类型:

public interface IApple { string GetName(); }
public interface IBanana { string GetName(); }

internal interface IFruit { string GetName(); }

class FruitAdaptor: IFruit
{
    public FruitAdaptor(string name) { this.name = name; }
    private string name;
    public string GetName() { return name; }
}

// convenience methods for fruit:
static class IFruitExtensions
{
    public static IFruit AsFruit(this IBanana banana)
    {
        return new FruitAdaptor(banana.GetName());
    }

    public static IFruit AsFruit(this IApple apple)
    {
        return new FruitAdaptor(apple.GetName());
    }
}

然后:

MethodThatNeedsFruit(banana.AsFruit());

您可以轻松地将其扩展,以便在适配的对象上懒惰地调用GetName,如果名称随时间而变化,则也可如此。
另一个选择是拥有仅在DEBUG模式下检查的方法,该方法确实加载所有IFruit实现者,然后如果其中一个实现者没有实际实现IBanana/IApple则抛出异常。由于这些类似乎是公司内部使用的,因此这应该可以防止任何人意外地实现错误的内容。

我猜那个方法可能会起作用,但它并没有真正提高代码的可读性。我选择了另一种解决方案,我更喜欢它,但我已经为其他人看到而点赞了这个方法。谢谢。 - Jasper
是的,但这大概是我能想到的唯一让它变得不可能的方法(当然,不考虑恶意代码)。 - porges

2

你想做的事情实际上是不可能的,但你可以在IFruit接口上使用[Obsolete]属性来阻止人们使用它,并附带原因说明。

在你的IBanana、IApple等接口中,禁用过时警告的出现。

[Obsolete]
public interface IFruit {
    ...
}

#pragma warning disable 612
public interface IBanana : IFruit {
    ...
}
#pragma warning restore 612

不是一个坏主意。通过实施检查策略,防止带有警告的代码被提交,这确实可以完全防止使用接口。谢谢! - Jasper

0

如果你的代码中有类似这样的内容(假设我正确理解了你的状态):

public class WaterMellon : IFruit, IVegetables...
{
}

如果你想让你的框架的使用者能够访问IFruit的方法,那么我所知道的唯一方法就是进行强制类型转换。

IFruit fruit = new WaterMelon();
fruit. //CAN ACCESS ONLY TO FRUIT IMPLEMNTATION AVAILABLE IN WATERMELON

如果这不是您所询问的,请澄清一下。


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