为什么在抽象类中,内部字段比保护字段更可取?

问题描述 投票:0回答:1

我有一个包含串口的设备的抽象类,衍生类也使用串口,但我不想让串口在这些衍生类之外可见。

public abstract class SerialDevice
{
    // serial port (should this be protected, internal, or protected internal?)
    protected SerialPort _serialPort;

    // The serial port has some shared methods.
    public void Open()
    {
        _serialPort.Open();
    }
}

衍生类也使用串口 但我不想让串口在这些衍生类之外可见

public class Widget : SerialDevice
{
    // The serial port has some widget-specific functionality.
    public void UniqueCommand()
    {
        _serialPort.WriteLine("Hello world.");
    }
}

当我编译时,我得到了这个警告。 CA1051: 不要声明可见的实例字段。,它说字段应该是一个隐藏的实现细节。 好吧,我可以使用一个受保护的属性来代替,保护我的类不被破坏。

但它继续推荐字段是私有的 或内部. 该 C#编程指南的访问修饰符页面 说,将串口设置为 "protected "允许它只在派生类中被访问,而将它设置为 "internal "则允许它在整个汇编中被访问。 那么为什么 "内部 "可以接受,而 "受保护 "就不行呢? 受保护的访问不是比内部访问更不明显吗?

相关的问题。 抽象类中的字段的可访问性应该是多少?

c# .net access-modifiers
1个回答
1
投票

为了实现封装,我们不应该将我们的字段直接暴露给外部,甚至是暴露给自己汇编内部的一个类。

相反,我们可以有一个内部的getter方法,这样只有我们汇编内部的类才能访问它,使用它,但不能改变它的引用。

如果我们再进一步,希望abstractbase类只能由我们自己的汇编中的类来扩展。

通过将基类公开,并指定所有构造函数为内部构造函数 我们可以确保只有我们自己的汇编中的类可以扩展它。

public abstract class SerialDevice
{
    private SerialPort _serialPort;

    internal SerialPort GetSerialPort()
    {
        return _serialPort;
    }

    // We define our base class public,
    // but also define all the constructors internal
    // Therefore, no class outside our assembly extend it
    // but we still can expose sub classes (like Widget) to the outside
    internal SerialDevice()
    {

    }

    // The serial port has some shared methods.
    // These methods are still visible from the outside
    public void Open()
    {
        _serialPort.Open();
    }
}

而且。

public class Widget : SerialDevice
{
    // The serial port has some widget-specific functionality.
    public void UniqueCommand()
    {
        GetSerialPort().WriteLine("Hello world.");
    }
}

1
投票

从某种程度上来说,protected比internal更明显,因为如果你扩展了这个类,你可以在汇编之外访问这个字段,但是internal却将它限制在定义了字段的一个汇编中。


0
投票

Oguz的答案很好,但我决定使用一个属性而不是方法。 所以我的解决方案是这样的,并且似乎符合最佳实践。

  • 抽象类是公开的,所以其他的汇编可以看到它。
  • 抽象类的构造函数是内部的,所以它不能在汇编之外继承。
  • 串行端口 "Port "是一个属性,而不是一个字段,所以它可以在抽象类内部稍后更改,而不会破坏任何派生类。
  • 属性 "Port "是受保护的,所以除了在基类的派生类中,不能看到它。
public abstract class SerialDevice
{
    // Constructor
    internal SerialDevice() {}

    // serial port
    protected SerialPort Port { get; } = new SerialPort();

    // The serial port has some shared methods.
    public void Open()
    {
        Port.Open();
    }
}
public class Widget : SerialDevice
{
    // The serial port has some widget-specific functionality.
    public void UniqueCommand()
    {
        Port.WriteLine("Hello world.");
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.