封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。
抽象和封装是面向对象程序设计的相关特性。抽象允许相关信息可视化,封装则使开发者实现所需级别的抽象。
C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。
一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:
声明的可访问性 | 含义 |
---|---|
public | 访问不受限制。 |
protected | 访问限于包含类或派生自包含类的类型。 |
internal | 访问限于当前程序集。 |
protected internal | 访问限于当前程序集或派生自包含类的类型。 |
private | 访问限于包含类。 |
private protected | 访问限于包含类或当前程序集中派生自包含类的类型。 |
成员 | 默认成员可访问性 | 允许的成员的声明的可访问性 |
---|---|---|
enum | public | 无 |
class | private | public protected internal private protected internal private protected |
interface | public | public protected internal private *protected internal private protected |
struct | private | public internal private |
* 具有 private
可访问性的 interface
成员必须具有默认的实现。
备注
如果使用 record 关键字修饰符修改类或结构,则允许相同的访问修饰符。
此外,使用 record 修饰符,类和结构的默认成员可访问性仍然为 private
。
Public 访问修饰符
Public 访问修饰符允许一个类将其成员变量和成员函数暴露给其他的函数和对象。任何公有成员可以被外部的类访问。
以下代码展示不同访问修饰符的区别和应用:
代码如下:
using System;
// 定义一个命名空间
namespace 空间1
{
// 外部类,用于展示不同访问级别的成员
public class 外部类1
{
// Public 成员,任何地方都可以访问
public int PublicField = 1;
// Private 成员,只能在定义它的类内部访问
private int PrivateField = 2;
// Internal 成员,只能在同一个程序集(Assembly)内访问
internal int InternalField = 3;
// Protected 成员,只能在定义它的类及其子类中访问
// 这里不直接展示,因为需要子类来演示
// Protected Internal 成员,在同一个程序集内的任何类或子类中都可以访问
protected internal int ProtectedInternalField = 4;
// 构造函数
public 外部类1()
{
Console.WriteLine($"PublicField: {PublicField}");
Console.WriteLine($"PrivateField: {PrivateField}"); // 内部访问,有效
Console.WriteLine($"InternalField: {InternalField}"); // 内部访问,有效
Console.WriteLine($"ProtectedInternalField: {ProtectedInternalField}"); // 内部访问,有效
}
// Public 方法,用于展示如何访问不同访问级别的成员
public void ShowFields()
{
Console.WriteLine($"PublicField: {PublicField}");
Console.WriteLine($"PrivateField: {PrivateField}"); // 内部访问,有效
Console.WriteLine($"InternalField: {InternalField}"); // 内部访问,有效
Console.WriteLine($"ProtectedInternalField: {ProtectedInternalField}"); // 内部访问,有效
}
}
// 子类,用于展示protected和protected internal的访问
public class 子类1 : 外部类1
{
public 子类1()
{
// 可以访问protected和protected internal成员,因为我们在同一个程序集内且是子类
Console.WriteLine($"Inherited ProtectedInternalField: {ProtectedInternalField}");
// 注意:这里不能直接访问PrivateField,因为它是私有的
// 如果尝试访问PrivateField,则会编译错误
}
// 演示访问protected和protected internal的方法
public void ShowInheritedFields()
{
// 可以访问从外部类1继承的protected和protected internal成员
Console.WriteLine($"Inherited ProtectedInternalField: {ProtectedInternalField}");
// 注意:这里不能直接访问PrivateField,因为它是私有的
}
}
class Program
{
static void Main(string[] args)
{
外部类1 outer = new 外部类1();
outer.ShowFields(); // 可以访问外部类1的public和internal成员
// 尝试访问private成员会导致编译错误
// Console.WriteLine($"PrivateField from Main: {outer.PrivateField}"); // 编译错误
// 演示子类
子类1 子类1 = new 子类1();
子类1.ShowInheritedFields(); // 演示从外部类1继承的protected和protected internal成员的访问
// 注意:由于Main在空间1命名空间中,所以它可以访问internal成员
// 但如果Main在另一个命名空间中且不属于同一个程序集,则不能访问InternalField
// 保持控制台开启
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
以下为官方代码:
public class 函数
{
public static int publicInt;
internal static int internalInt;
private static int privateInt = 0;
static 函数()
{
// T1 can access public or internal members
// in a public or private (or internal) nested class.
M1.publicInt = 1;
M1.internalInt = 2;
M2.publicInt = 3;
M2.internalInt = 4;
// Cannot access the private member privateInt
// in either class:
// M1.privateInt = 2; //CS0122
}
public class M1
{
public static int publicInt;
internal static int internalInt;
private static int privateInt = 0;
}
private class M2
{
public static int publicInt = 0;
internal static int internalInt = 0;
private static int privateInt = 0;
}
}
class MainClass
{
static void Main()
{
// Access is unlimited.
函数.publicInt = 1;
// Accessible only in current assembly.
函数.internalInt = 2;
// Error CS0122: inaccessible outside T1.
// T1.privateInt = 3;
// Access is unlimited.
函数.M1.publicInt = 1;
// Accessible only in current assembly.
函数.M1.internalInt = 2;
// Error CS0122: inaccessible outside M1.
// 函数.M1.privateInt = 3;
// Error CS0122: inaccessible outside T1.
// 函数.M2.publicInt = 1;
// Error CS0122: inaccessible outside T1.
// 函数.M2.internalInt = 2;
// Error CS0122: inaccessible outside M2.
// 函数.M2.privateInt = 3;
// Keep the console open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}