windows C#-命名空间和类
命名空间
在 C# 编程中,命名空间在两个方面被大量使用。 首先,.NET 使用命名空间来组织它的许多类,如下所示:
System.Console.WriteLine("Hello World!");
System 是一个命名空间,Console 是该命名空间中的一个类。 可使用 using 关键字,这样就不必使用完整的名称,如下例所示:
using System;
Console.WriteLine("Hello World!");
其次,在较大的编程项目中,声明自己的命名空间可以帮助控制类和方法名称的范围。 使用 namespace 关键字可声明命名空间,如下例所示:
namespace SampleNamespace
{class SampleClass{public void SampleMethod(){System.Console.WriteLine("SampleMethod inside SampleNamespace");}}
}
命名空间的名称必须是有效的 C# 标识符名称。
从 C# 10 开始,可以为该文件中定义的所有类型声明一个命名空间,如以下示例所示:
namespace SampleNamespace;class AnotherSampleClass
{public void AnotherSampleMethod(){System.Console.WriteLine("SampleMethod inside SampleNamespace");}
}
这种新语法的优点是更简单,这节省了水平空间且不必使用大括号。 这使得你的代码易于阅读。
命名空间具有以下属性:
- 它们组织大型代码项目;
- 通过使用 . 运算符分隔它们;
- using 指令可免去为每个类指定命名空间的名称;
- global 命名空间是“根”命名空间:global::System 始终引用 .NET System 命名空间;
引用类型
定义为 class 的类型是引用类型。 在运行时,如果声明引用类型的变量,此变量就会一直包含值 null,直到使用 new 运算符显式创建类实例,或直到为此变量分配已在其他位置创建的兼容类型,如下面的示例所示:
//Declaring an object of type MyClass.
MyClass mc = new MyClass();//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;
创建对象时,在该托管堆上为该特定对象分足够的内存,并且该变量仅保存对所述对象位置的引用。 对象使用的内存由 CLR 的自动内存管理功能(称为垃圾回收)回收。
声明类
使用后跟唯一标识符的 class 关键字可以声明类,如下例所示:
//[access modifier] - [class] - [identifier]
public class Customer
{// Fields, properties, methods and events go here...
}
可选访问修饰符位于 class 关键字前面。 class 类型的默认访问权限为 internal。 此例中使用的是 public,因此任何人都可创建此类的实例。 类的名称遵循 class 关键字。 类名称必须是有效的 C# 标识符名称。 定义的其余部分是类的主体,其中定义了行为和数据。 类上的字段、属性、方法和事件统称为类成员。
创建对象
虽然它们有时可以互换使用,但类和对象是不同的概念。 类定义对象类型,但不是对象本身。 对象是基于类的具体实体,有时称为类的实例。
可通过使用 new 关键字,后跟类的名称来创建对象,如下所示:
Customer object1 = new Customer();
创建类的实例后,会将一个该对象的引用传递回程序员。 在上一示例中,object1 是对基于 Customer 的对象的引用。 该引用指向新对象,但不包含对象数据本身。 事实上,可以创建对象引用,而完全无需创建对象本身:
Customer object2;
不建议创建不引用对象的对象引用,因为尝试通过这类引用访问对象会在运行时失败。 但是,但实际上引用可以引用某个对象,方法是创建新对象,或者将其分配给现有对象,例如:
Customer object3 = new Customer();
Customer object4 = object3;
此代码创建指向同一对象的两个对象引用。 因此,通过 object3 对对象做出的任何更改都会在后续使用 object4 时反映出来。 由于基于类的对象是通过引用来实现其引用的,因此类被称为引用类型。
构造函数和初始化
前面的部分介绍了声明类类型并创建该类型的实例的语法。 创建类型的实例时,需要确保其字段和属性已初始化为有用的值。 可通过多种方式初始化值:
- 接受默认值
- 字段初始化表达式
- 构造函数参数
- 对象初始值设定项
每个 .NET 类型都有一个默认值。 通常,对于数字类型,该值为 0,对于所有引用类型,该值为 null。 如果默认值在应用中是合理的,则可以依赖于该默认值。
当 .NET 默认值不是正确的值时,可以使用字段初始化表达式设置初始值:
public class Container
{// Initialize capacity field to a default value of 10:private int _capacity = 10;
}
可以通过定义负责设置初始值的构造函数来要求调用方提供初始值:
public class Container
{private int _capacity;public Container(int capacity) => _capacity = capacity;
}
从 C# 12 开始,可以将主构造函数定义为类声明的一部分:
public class Container(int capacity)
{private int _capacity = capacity;
}
向类名添加参数可定义主构造函数。 这些参数在包含其成员的类正文中可用。 可以将其用于初始化字段或需要它们的任何其他位置。
还可以对某个属性使用 required 修饰符,并允许调用方使用对象初始值设定项来设置该属性的初始值:
public class Person
{public required string LastName { get; set; }public required string FirstName { get; set; }
}
添加 required 关键字要求调用方必须将这些属性设置为 new 表达式的一部分:
var p1 = new Person(); // Error! Required properties not set
var p2 = new Person() { FirstName = "Grace", LastName = "Hopper" };
类继承
类完全支持继承,这是面向对象的编程的基本特点。 创建类时,可以从其他任何未定义为 sealed 的类继承。 其他类可以从你的类继承并替代类虚拟方法。 此外,你可以实现一个或多个接口。
继承是通过使用派生来完成的,这意味着类是通过使用其数据和行为所派生自的基类来声明的。 基类通过在派生的类名称后面追加冒号和基类名称来指定,如:
public class Manager : Employee
{// Employee fields, properties, methods and events are inherited// New Manager fields, properties, methods and events go here...
}
类声明包括基类时,它会继承基类除构造函数外的所有成员。
C# 中的类只能直接从基类继承。 但是,因为基类本身可能继承自其他类,因此类可能间接继承多个基类。 此外,类可以支持实现一个或多个接口。
类可以声明为 abstract。 抽象类包含抽象方法,抽象方法包含签名定义但不包含实现。 抽象类不能实例化。 只能通过可实现抽象方法的派生类来使用该类。 与此相反,密封类不允许其他类继承。
类定义可以在不同的源文件之间分割。