【问题标题】:Why interface have only public member and methods为什么接口只有公共成员和方法
【发布时间】:2014-10-26 11:02:34
【问题描述】:

这是一个非常基本的面试问题,我们可以在接口内声明一个方法为私有,我的回答很简单,接口中只有公共变量或方法,然后出现下一个问题......为什么?

【问题讨论】:

  • 如果是私有的,你会如何实现接口?
  • 不能对成员和方法进行保护/打包吗?私有意味着它们无法实现,所以这可能是它不合逻辑的原因,但关于受保护和打包这可能是有意义的。
  • @Hybris95:强制实施受保护的接口有什么价值?
  • @DimitrisKalaitzis 请记住,我们在这里讨论的是 C# 规范而不是 Java。

标签: c#


【解决方案1】:

对于界面成员如何具有不同的可见性有多种解释。虽然标识符的可见性可能有更多可以想象的级别,但让我们看看 C# 中可用的那些级别,并考虑它们是否可以有意义地集成到接口中。

1) 接口成员仅对基于相应可见性级别的规则的接口之外的代码可见。

  • public:C# 中的接口成员默认是公共的,所以这是可行的。
  • internal:如果单个接口成员可以声明为internal,则意味着接口的一部分只能由接口所在程序集的类实现。类似的情况已经存在于抽象的情况下抽象类的类成员或构造函数被声明为internal - 这有效地防止了基类程序集之外的子类化。
    至于可能使用它的场景,请考虑返回对象的 API,这些对象稍后会被所述 API 再次使用。如果由于某种原因,API 只能使用它自己实例化的对象,则能够以第 3 方代码无法派生其自定义类的方式声明基类,而只能使用从 API 获得的内容,而不是能够对界面做同样的事情感觉奇怪的不对称。
  • protected:受保护的成员仅在其自己的类及其任何子类中可见。应用与上述相同的假设,这意味着只有接口声明本身的代码(嗯,接口几乎不包含可能相关的代码1),派生接口(与以前相同) ),并且可能实现该接口的类可以看到那些受保护的成员。
    后一种情况是事情可能变得有趣的地方,如果只是在相当人为的情况下:该类中的方法可能想要使用实现接口的任何东西,无论是类本身的当前实例,还是嵌套在其中的任何其他类型,而获得对受保护方法的半独占访问权。
  • private:具有private 可见性的所有内容仅对声明接口本身可见。由于接口成员很难1在接口本身内被引用,这可能不是很有用。但是,可能仍然存在一些极端情况,例如接口中的const 定义在所述接口的属性中被引用,但不应被外部代码使用 - 但是,C# does not allow for const values in interfaces,即使a similar feature is not unprecedented in the CLI world。李>

2) 接口成员必须以(至少?)接口中指定的可见性来实现,并在通过类型化到类的引用访问成员时遵守该可见性,但在访问时通常是公开可见的成员通过键入接口的引用。

同样,public 成员的情况不会发生变化,而 internalprotectedprivate 可见性将允许接口允许明显部分实现。目前可以通过显式接口实现来实现类似的效果,因此在某些方面,这将是避免编写相同方法两次的语法糖,一次具有预期的可见性,一次具有特定于接口的显式实现声明(即使后者通常只转发呼叫)。

3) 为了完整起见,即使您的问题听起来不像包含此选项:对于每个类,整个接口的可见性由实现者确定。

像这样,一个类可以实现一个接口,但这一事实只会在相应的可见性级别内显而易见,而在外部,该类根本不会被认为与该接口的赋值兼容或可转换。
如果接口本身需要比类更小的可见性,这可能特别有用,因为接口应该只在内部处理,对外部世界没有意义。 目前,这在 C# 中是不可能的;接口至少需要与其实现类一样可访问。 但是,这也可以通过公共类中的implementing an internal interface 来实现。


由于界面成员的可见性可能有很多方法,并且至少在某些情况下是有用的,所以这个问题最明确的答案可能是 “因为开发团队决定以这种方式指定 C# "

1据推测,C# 6 的nameof 运算符可用于同一接口的属性声明中的受保护/私有接口成员。

【讨论】:

    【解决方案2】:

    接口是类需要实现的契约,以确保某些给定类的使用者将接收强制实现接口的类的实例。

    如果接口允许私有成员,那么您无法调用对公共表面隐藏的接口成员这一事实将违背接口的目的,因为消费者将无法调用这些私有成员(那么...为什么它会使用接口?)。

    例如,接口为对象提供类型。如果某些消费者代码依赖于接收实现某个接口的对象以避免对使用它的程序集的冗余依赖,并且整个程序集可以访问不公开提供成员的接口,那么该消费者将如何使用所谓的对象?

    public interface IDoesSomething
    {
         private void Do();
    } 
    
    public void SomeMethod(IDoesSomething some) 
    {
        some.????? // <---- what? the object doesn't have public members!
    }
    

    事实上,由于接口只是元数据,我知道您可能会认为“我会声明私有成员以强制实现者以预期的顺序调用某些逻辑”,但同样,因为它们'只是元数据,您无法确保某些公共成员会以正确的顺序调用私有成员。并且实现将无法访问接口私有成员,因为他们需要为此受到保护这就是抽象类存在的原因)...

    【讨论】:

    • 将内部接口的成员实现为内部方法/属性可能是合乎逻辑的。可悲的是,这不是语言的设计方式。
    • @Ndech 我会说内部接口是可能的。这是一个必需的设计决策:您的界面是 100% 公开的或 100% 内部的,否则它也会违背界面的目的。
    • @MatíasFidemraizer:我可以想象具有公共和内部成员的接口。内部成员对其他程序集是不可见的(因此无法在那里实现接口,类似于只给抽象类提供内部构造函数时)。这可能是将类型为此类接口类型的方法参数限制为由也声明接口的程序集声明的类的一种优雅方式。它们的工作方式类似于类中的内部成员。
    • @O.R.Mapper 也许你是对的,但我看不出任何库都无法实现的接口的意义。我的意思是,这不是接口的目的。我错了吗?如果你使用接口是因为你想发布一些 API,所以它提供默认实现,但是如果它的行为像消费者期望的那样,同一个提供者可能会接受任何实现......
    • @MatíasFidemraizer:问题询问为什么 C# 不允许除公共以外的任何接口成员可见性。当您阅读有关此问题的所有答案和 cmets 时,您会看到各种用户写了一些类似“C# 中的接口成员只能是公共的,因为这是唯一有意义的方式”。我通过展示内部接口成员如何也有用,简单地解释了为什么我不同意这种说法。 问题不是问什么是或不是当前 C# 实现的一部分,而是专门询问原因。
    【解决方案3】:

    接口具有由某些实现提供的公共合约语义。它就像类(或全局模块、子系统、组件……)为其客户端提供的 API。 私有方法用于处理一些内部逻辑,因此取决于实际实现是什么。它取决于上下文。因此,如果类客户端需要调用私有方法,那么 1) 它必须是公共的,或者 2) 存在不好的设计实践。

    这就是为什么抽象接口可以被认为是OOP的基础,它是实现抽象、封装和多态等事物的非常重要的工具。

    【讨论】:

      【解决方案4】:

      答案太简单了;

      当一个类从一个接口扩展时,这个接口的成员和方法应该可以被这个类访问,这就是为什么你必须是公共的

      【讨论】:

        猜你喜欢
        • 2013-04-11
        • 2012-03-28
        • 2016-07-28
        • 2021-10-06
        • 1970-01-01
        • 2017-06-08
        • 1970-01-01
        • 1970-01-01
        • 2017-11-23
        相关资源
        最近更新 更多