C# 接口的非公共成员 [关闭]

Posted

技术标签:

【中文标题】C# 接口的非公共成员 [关闭]【英文标题】:Non Public Members for C# Interfaces [closed] 【发布时间】:2010-09-06 06:20:45 【问题描述】:

在 C# 中,当您实现一个接口时,所有成员都是隐式公共的。如果我们可以指定可访问性修饰符(protectedinternal,当然private 除外)不是更好,还是应该只使用抽象类?

【问题讨论】:

如果你显式实现它,你可以从 API 中隐藏接口。 可能会出现在 C# 8.0 jeremybytes.blogspot.com/2019/11/… 【参考方案1】:

如果接口是内部的,则其所有成员都将在程序集内部。如果嵌套接口受到保护,则只有外部类的子类可以访问该接口。

在其声明程序集之外的接口的内部成员将毫无意义,在其声明的外部类之外的接口的受保护成员也是如此。

接口的意义在于描述实现类型和接口用户之间的契约。外部调用者不会关心也不应该不得不关心实现,这是内部成员和受保护成员的用途。

对于基类调用的受保护成员,抽象类是在基类和继承自它们的类之间指定契约的方法。但是在这种情况下,实现细节通常是非常相关的,除非它是一个退化的纯抽象类(其中 all 成员都是抽象的),在这种情况下受保护的成员是无用的。在这种情况下,使用接口并保存单个基类以供选择实现类型。

【讨论】:

“该界面的用户”是什么意思?所以当你创建一个变量时让我们说 IMyInterface someVar;然后以某种方式使用 someVar? 我还可以补充一点,即使您没有将接口暴露给外部客户端,接口也会强制您的应用程序结构(其中的类)采用模式/共性...对吗?? 我认为拥有internal 成员的接口很有用。如果程序集 Foo 可以包含带有 internal 成员的接口 IWoozle,并且如果它包含 IWoozle 的五个实现,则任何地方的代码都可以传递 IWoozle 的实例,并使用它的公共成员,但接收到 @ 的代码987654326@ 会知道它是在程序集 Foo 中实现的。例如,假设接口IImmutableWoozle。实现可能并不都共享一个共同的基类型,但如果在 Foo 之外不存在任何实现,那么... ...Foo 中的代码,或者相信 Foo 不会做任何讨厌的事情的代码,可以知道 IImmutableWoozle 不会是一些古怪的可变实现。 在这种情况下,您可以创建一个内部接口IInternalWoozle,它实现了IWoozle,并且Foo中使用任何IWoozle的任何代码都可以检查IInternalWoozle是否也按顺序实现获取内部成员。 .NET 框架在某些地方就是这样做的。【参考方案2】:

您可以隐藏几乎所有由外部程序集接口实现的代码。

interface IVehicle

    void Drive();
    void Steer();
    void UseHook();

abstract class Vehicle  // :IVehicle  // Try it and see!

    /// <summary>
    /// Consuming classes are not required to implement this method.
    /// </summary>
    protected virtual void Hook()
    
        return;
    

class Car : Vehicle, IVehicle

    protected override void Hook()  // you must use keyword "override"
    
        Console.WriteLine(" Car.Hook(): Uses abstracted method.");
    
    #region IVehicle Members

    public void Drive()
    
        Console.WriteLine(" Car.Drive(): Uses a tires and a motor.");
    

    public void Steer()
    
        Console.WriteLine(" Car.Steer(): Uses a steering wheel.");
    
    /// <summary>
    /// This code is duplicated in implementing classes.  Hmm.
    /// </summary>
    void IVehicle.UseHook()
    
        this.Hook();
    

    #endregion

class Airplane : Vehicle, IVehicle

    protected override void Hook()  // you must use keyword "override"
    
        Console.WriteLine(" Airplane.Hook(): Uses abstracted method.");
    
    #region IVehicle Members

    public void Drive()
    
        Console.WriteLine(" Airplane.Drive(): Uses wings and a motor.");
    

    public void Steer()
    
        Console.WriteLine(" Airplane.Steer(): Uses a control stick.");
    
    /// <summary>
    /// This code is duplicated in implementing classes.  Hmm.
    /// </summary>
    void IVehicle.UseHook()
    
        this.Hook();
    

    #endregion

这将测试代码。

class Program

    static void Main(string[] args)
    
        Car car = new Car();
        IVehicle contract = (IVehicle)car;
        UseContract(contract);  // This line is identical...
        Airplane airplane = new Airplane();
        contract = (IVehicle)airplane;
        UseContract(contract);  // ...to the line above!
    

    private static void UseContract(IVehicle contract)
    
        // Try typing these 3 lines yourself, watch IDE behavior.
        contract.Drive();
        contract.Steer();
        contract.UseHook();
        Console.WriteLine("Press any key to continue...");
        Console.ReadLine();
    

【讨论】:

【参考方案3】:

您可以通过在方法名称之前显式声明接口名称来隐藏接口的实现:

public interface IInterface 
    public void Method();


public class A : IInterface 
    public void IInterface.Method() 
        // Do something
    


public class Program 
    public static void Main() 
        A o = new A();
        o.Method(); // Will not compile
        ((IInterface)o).Method(); // Will compile
    

【讨论】:

只是一个评论:现在你不能在接口成员或显式实现的接口方法中使用public 修饰符。例如,为了让您的代码与 .NET 4.5 一起使用,只需删除两个 publics。 安德鲁,你指的是哪两个公众? 为什么o.Method() 不编译?有人可以解释一下吗?为什么说接口名会隐藏接口实现? 凯尔。这种表示法(使用接口名称实现方法)被称为显式接口实现,我认为,它的目的是隐藏外部调用的方法(除了显式转换然后调用)。这在某些情况下非常有用。例如,基类可以在接口方法的实现中执行一次性操作。如果外部调用者可以看到该方法,他们可能会多次调用该方法并破坏基类的工作状态。【参考方案4】:

在我看来,这违反了封装。我必须实现一个公开的方法,然后我实现一个接口。我认为没有理由在实现接口的类中强制公开。 (c#)

【讨论】:

【参考方案5】:

这里的所有答案或多或少都说接口就是这样,它们是通用的公共规范。

这是讨论最多的话题,当我想到这个问题时,让我发布我在 SO 上找到的两个很好的答案。

This answer gives an example 在派生类中为接口成员使用非统一访问说明符是多么荒谬。代码总是比技术描述好。

对我来说,强制公共接口成员最糟糕的是接口本身可以在程序集内部,但它公开的成员必须是公共的。 Jon Skeet explains here that's by design sadly.

这提出了一个问题,为什么接口没有设计为对成员进行非公共定义。这可以使合同灵活。这在编写不希望类的特定成员暴露给程序集外部的程序集时非常有用。我不知道为什么。

【讨论】:

【参考方案6】:

接口是所有实现类都遵守的契约。这意味着他们必须遵守全部或不遵守。

如果接口是公开的,那么该联系人的每个部分都必须是公开的,否则对于朋友/内部类来说意味着一个,而对于其他一切来说就不同了。

要么使用抽象基类,要么(如果可能且可行)internal extension method on the interface。

【讨论】:

如果要声明一个公共抽象类,其所有成员和构造函数都是internal,那么外部代码可以从程序集中接收对该类型事物的引用,并将这些引用传回给程序集的方法,同时始终保持类型安全,而外部代码不必知道有关类的任何信息。不幸的是,这种方法只有在抽象类的具体派生都不需要继承任何不是从该抽象类派生的东西时才有效。 一个包含内部成员的接口,如果允许的话,会很像前面提到的抽象类,但优点是它可以由派生自没有的类的类来实现。 .【参考方案7】:

接口在它们的方法中没有访问修饰符,让它们对合适的访问修饰符开放。这有一个目的:它允许其他类型推断出哪些方法和属性可用于遵循接口的对象。为它们提供受保护/内部访问器会破坏接口的目的。

如果您坚持需要为方法提供访问修饰符,请将其留在接口之外,或者如您所说,使用抽象类。

【讨论】:

允许其他(读取外部)类型推断对象可用的方法和属性是一个受欢迎的选择吗?我会说对象应该能够决定什么应该可供外部世界推断。 准确地说,nawfal——接口是契约,而不是对象。应该使用接口来描述可用的行为,而不是定义实现细节。 乔恩,今天我意识到这是一个合同。不仅仅是一份合同,更像是一份“面向全世界的公共规范”。我在质疑这个原则,但是当人们说出来的时候,他们听起来就像“为什么接口成员是公开的?”经常找到的答案是“它是那种合同”的味道。 @Jon Skeet says here 是这样,因为是这样。 Here 是具有非公共接口成员的另一个含义。 但现在我想知道为什么接口本身中的成员定义不能是私有的、公共的等。到目前为止,我认为接口的存在也是为了强制类设计(涉及公共、受保护、私有等成员) ) 并且仍然觉得应该有一些东西来执行它。 迟到的答案,但想象一下公共界面中的私人成员。如果一个类甚至不知道它们的存在,它应该如何实现接口的所有成员?当然类似于其他修饰符。正如在接受的答案中指出的那样,您可以限制对接口本身的访问,从而防止任何尝试甚至在您不应该执行合同时执行合同。可以这么说,私有/受保护/内部接口就像其他人不知道的合同。与非公共成员的接口就像不明确的合同,可能无法完全实施。【参考方案8】:

我熟悉 Java 而不是 C#,但是为什么你会想要一个接口中的私有成员呢?它不能有任何实现,并且对于实现类是不可见的,所以没有用。存在接口来指定行为。如果您需要默认行为而不是使用抽象类。

【讨论】:

内部成员有意义吗? 我认为可以在内部声明整个接口(而不是单个方法)。这更有意义。 @JonLimjap 这是可能的,它唯一的好处是,它按预期隐藏了外部程序集的接口,但它们仍然要求其成员是公共的(这很奇怪),这意味着那些公共属性和方法对外界可见!!【参考方案9】:

没有意义。接口是与您支持这些方法和属性的public 的合同。坚持使用抽象类。

【讨论】:

一个“内部”访问修饰符对于接口来说似乎是一个非常有用的东西;在其任何成员上具有此类修饰符的接口只能由声明它的程序集中的代码实现,但可以由任何地方的代码使用。我可以看到很多用途。 我不认为接口被用作强类型指南或同一程序集中代码的脚手架。我相信他们的主要目的是与外界“交互”。 假设程序集定义了 BankCheckingAccount、CreditUnionCheckingAccount、BankSavingsAccount 和 CreditUnionSavingsAccount。银行账户具有信用合作社账户所缺乏的功能,反之亦然。支票账户具有储蓄账户所缺乏的功能,反之亦然。拥有支票账户、储蓄账户、银行账户和信用合作社账户的类型会很有帮助,但只能对这四个中的两个使用抽象类。如果抽象类的继承仅限于同一个程序集... ...可以确定 CheckingAccount 是 BankCheckingAccount 或 CreditUnionCheckingAccount,而不是 JoeHackerPhonyCheckingAccount。能够为 IBankAccount 接口(由 BankCheckingAccount 和 BankSavingsAccount 实现)或 ICreditUnionAccount 接口(由 CreditUnionCheckingAccount 和 CreditUnionSavingsAccount 实现)提供类似的保证会很有帮助。 [当然,并不是说人们会将真实的财务信息信任到班级级别的安全性——这只是一个类比]。 “接口是与公众签订的支持这些方法和属性的合同” - 我不同意这一点,我会说接口是(或应该是)与实施者的合同.而且我应该能够强制执行某些私有方法和属性。

以上是关于C# 接口的非公共成员 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C# 基础知识

Java2C#翻译:C#接口中的公共方法

在 C# 中,我们可以对接口使用受保护的访问修饰符吗?

[翻译] C# 8.0 接口默认实现

C#接口学习

静态类无法实现接口