内部接口实现

17

直接说问题:我有一个实现了两个接口的类:

public class A : Interface1, Interface2{
   // Interface 1 implementation...
   // Interface 2 implementation...
}

有没有一种方法(不需要创建另一个新类)使Interface1的实现内部化并将其隐藏在其他组件中(只有Interface2保持公开)?

编辑:还有一些有用的信息:Interface1和Interface2在另一个核心组件中定义为public,无法更改。

提前致谢,


3
将接口设置为内部的?internal interface Interface1 除此之外没有其他选项,因为按照定义,接口是公开契约。 - Adam Houldsworth
谢谢,不幸的是两个接口都是公共的,无法更改(请参见编辑)。 - GETah
1
嗯...如果...创建一个新的接口internal interface Interface3:Interface1并在目标类中实现它,那么Interface1仍然是公共的,但我们会得到想要的结果。抱歉,我错了,这行不通。 - Alexander Mavrinsky
2个回答

35

尽管你可以将接口本身设为 internal,但方法仍然会成为公共 API 的一部分。你可以选择使用显式接口实现,这样由接口定义的 API 只能通过接口访问,而不能通过类访问。

interface IFoo
{
     void M();
}

interface IBar
{
     void X(); 
}

public class Bar : IBar, IFoo
{
    public void X() // part of the public API of Bar
    {
    }

    void IFoo.M() // explicit implementation, only visible via IFoo
    {
    }
}

Bar bar = new Bar();
bar.X(); // visible
bar.M(); // NOT visible, cannot be invoked
IFoo foo = bar;
foo.M(); // visible, can be invoked

如果你希望世界上永远不知道这个类支持接口,那么你只需要让这个类不实现该接口。接口的作用在于传达给定对象明确或隐含地支持特定行为的意图。如果这不是你想要的,你需要采取不同的方向。可以将该类实现的行为视为私有实现细节而不使用接口。另一种方法是将这些实现推入私有嵌套类中。

public class Bar : IBar
{
    Foo foo = new Foo();

    public void X() { }   

    public void DoSomething()
    {
        this.foo.M(); // invokes method of instance of nested class
    }

    class Foo : IFoo
    {
        public void M() { } 
    }
}

根据这种方法,世界永远不会知道一个类是否满足接口契约,因为从技术上讲它并没有。 契约由Foo履行,而且世界看不到Foo。但是,好处在于如果该类需要调用需要接口的外部定义方法,则仍然可以将嵌套类实例传递给这些方法。


+1 感谢您的回答。这似乎接近我所需要的。然而,我正在寻找一种完全禁止 IFoo foo = bar; 的方法,这是否可能? - GETah
2
@GETah,如果你将显式接口实现与内部接口结合使用,就可以有效地限制对给定库的访问。如果你无法控制接口定义(就像在你的情况下),这不是一个选择。 - Anthony Pegram
@GETah,查看更新后的答案以获取更多想法(评论已修订并添加到答案中,附带代码)。 - Anthony Pegram
谢谢,我的类需要实现Interface1的原因是因为我有其他内部类需要这个服务。我对你的答案非常满意,非常感谢你的时间和努力 :) - GETah

3

无法将强制类型转换操作限制为接口。但是,您可以提供一个实现接口的包装类,但通常不可用。

例如:

public class Foo
{
    private IFoo wrap = new WrapFoo(this);

    internal IFoo GetIFoo()
    {
        return wrap;
    }

    private class WrapFoo : IFoo
    {
        public WrapFoo(Foo parent)
        {
            //Save parent
        }

        public void DoSomething()
        {
            //Implement interface
        }
    }
}

另一种更复杂的方法是使用代码签名来验证调用者是否为库,否则会抛出异常。

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