为什么内部字段优于抽象 class 中的受保护字段?
Why are internal fields preferable to protected fields in an abstract class?
我有一个包含串行端口的设备的摘要class:
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();
}
}
Derived classes 也使用串行端口,但我不希望端口在那些 derived classes 之外可见。
public class Widget : SerialDevice
{
// The serial port has some widget-specific functionality.
public void UniqueCommand()
{
_serialPort.WriteLine("Hello world.");
}
}
当我编译时,我得到这个警告:CA1051: Do not declare visible instance fields,它说字段应该是一个隐藏的实现细节。好的,我可以使用受保护的 属性 来保护我的 classes 免受破坏内容的更改。
但它继续建议字段是私有的或内部的。 C# Programming Guide's page on Access Modifiers 表示使串行端口 "protected" 只允许在派生的 classes 中访问它,而使它成为 "internal" 将允许它在整个程序集中访问.那么为什么 "internal" 可以接受,而 "protected" 不可以呢?受保护的访问不是比内部访问更不可见吗?
相关问题:What should the accessablity of Fields in a Abstract Class be?
在某种程度上,protected 比 internal 更明显,因为如果您扩展 class,则可以访问程序集外部的字段,但 internal 将其限制在定义该字段的那个程序集中。
为了实现封装,我们不应该将我们的字段直接暴露给外部,即使是我们自己的程序集内的 class。
相反,我们可以有一个内部 getter 方法,这样只有我们程序集中的 classes 可以访问它,使用它,但不能更改它的引用。
如果我们更进一步,希望 abstract/base class 只能由我们自己的程序集中的 classes 扩展:
通过使用基础 class public 并将所有构造函数指定为内部构造函数,我们可以确保只有 class 在我们自己的程序集中可以扩展它。
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.");
}
}
Oguz 的回答很好,但我决定使用 属性 而不是方法。所以我的解决方案看起来像这样,并且似乎符合最佳实践。
- 摘要 class 是 public,因此程序集的其余部分可以看到它。
- 抽象 class' 构造函数是内部的,因此不能在程序集外部继承。
- 串口,"Port,"是一个属性,不是一个字段,所以以后可以在抽象class中改变它,而不会破坏任何派生的[=26] =]es.
- 属性 "Port" 受到保护,因此只能在 class 派生自基数 class 的 class 中看到它。
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.");
}
}
我有一个包含串行端口的设备的摘要class:
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();
}
}
Derived classes 也使用串行端口,但我不希望端口在那些 derived classes 之外可见。
public class Widget : SerialDevice
{
// The serial port has some widget-specific functionality.
public void UniqueCommand()
{
_serialPort.WriteLine("Hello world.");
}
}
当我编译时,我得到这个警告:CA1051: Do not declare visible instance fields,它说字段应该是一个隐藏的实现细节。好的,我可以使用受保护的 属性 来保护我的 classes 免受破坏内容的更改。
但它继续建议字段是私有的或内部的。 C# Programming Guide's page on Access Modifiers 表示使串行端口 "protected" 只允许在派生的 classes 中访问它,而使它成为 "internal" 将允许它在整个程序集中访问.那么为什么 "internal" 可以接受,而 "protected" 不可以呢?受保护的访问不是比内部访问更不可见吗?
相关问题:What should the accessablity of Fields in a Abstract Class be?
在某种程度上,protected 比 internal 更明显,因为如果您扩展 class,则可以访问程序集外部的字段,但 internal 将其限制在定义该字段的那个程序集中。
为了实现封装,我们不应该将我们的字段直接暴露给外部,即使是我们自己的程序集内的 class。
相反,我们可以有一个内部 getter 方法,这样只有我们程序集中的 classes 可以访问它,使用它,但不能更改它的引用。
如果我们更进一步,希望 abstract/base class 只能由我们自己的程序集中的 classes 扩展:
通过使用基础 class public 并将所有构造函数指定为内部构造函数,我们可以确保只有 class 在我们自己的程序集中可以扩展它。
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.");
}
}
Oguz 的回答很好,但我决定使用 属性 而不是方法。所以我的解决方案看起来像这样,并且似乎符合最佳实践。
- 摘要 class 是 public,因此程序集的其余部分可以看到它。
- 抽象 class' 构造函数是内部的,因此不能在程序集外部继承。
- 串口,"Port,"是一个属性,不是一个字段,所以以后可以在抽象class中改变它,而不会破坏任何派生的[=26] =]es.
- 属性 "Port" 受到保护,因此只能在 class 派生自基数 class 的 class 中看到它。
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.");
}
}