C#学习笔记-C#基础知识-C#从入门到放弃-C#结构、类与属性
- 人工智能
- 2025-07-21 19:08:22

C# 入门基础知识 - C# 结构、类与属性 第9节 结构、类与属性9.1 结构的使用9.2 枚举9.3 面向对象概述9.4 类与对象的关系9.5 类的声明9.6 属性的使用9.6.1 属性9.6.2 属性使用 9.7 构造函数和析构函数9.7.1 构造函数9.7.2 析构函数 9.8 类的继承9.9 类的封装9.10 类的多态
更多C#基础知识点可查看:C#学习笔记 - C#基础知识 - C#从入门到放弃
第9节 结构、类与属性 9.1 结构的使用在C#中,结构(Struct)是一种用户自定义的数据类型,用于封装多个相关的值。与类(Class)不同,结构是值类型(Value Type),而不是引用类型(Reference Type)。
【示例程序代码】 一次性声明多个不同类型的变量
namespace 结构的使用 { //结构放于此空间,所有类都可访问 public struct ClerkInfo { public string name; public int age; public string department; public char sex; } class Program { //如果放于此位置,只有当前Program类或继承类可以访问 static void Main(string[] args) { ClerkInfo c1 = new ClerkInfo(); c1.name = "Flyer"; c1.age = 24; c1.department = "数据库维护部"; c1.sex = '男'; Console.WriteLine("我是{0},{3}生,今年{1}岁,工作于{2}。",c1.name,c1.age,c1.department,c1.sex); Console.ReadKey(); } } }运行程序:
我是Flyer,男生,今年24岁,工作于数据库维护部。在示例代码中出现的一些使用结构的常见情况和示例说明: 1、声明结构: 要声明一个结构,可以使用 struct 关键字,后面跟着结构的名称和定义结构的内容。
public struct ClerkInfo { public string name; public int age; public string department; public char sex; }2、创建结构的实例: 可以使用 new 关键字创建结构的实例。
ClerkInfo c1 = new ClerkInfo();3、结构的成员访问: 结构的成员可以通过点符号进行访问。
c1.name = "Flyer"; c1.age = 24; c1.department = "数据库维护部"; c1.sex = '男';4、方法和属性: 结构可以包含方法和属性来定义结构的行为和操作。
可以为示例代码结构添加一个方法来打印结构的信息:
public struct ClerkInfo { public string name; public int age; public string department; public char sex; //可以在结构中添加一个打印信息功能 public void PrintInfo() { Console.WriteLine("Name: {0}, Age: {1}",name,age); } }然后,可以通过结构的实例调用该方法:
ClerkInfo c2 = new ClerkInfo() { name = "程饱饱吃得好饱", age = 24 }; c2.PrintInfo();运行程序:
Name: 程饱饱吃得好饱, Age: 245、结构作为参数和返回值: 结构可以作为方法的参数和返回值。当作为参数传递时,会进行值的复制。
public void updateClerkInfoName(string newName) { c.name = newName; } //当作为返回值返回时,会复制整个结构的值 // 将 getClerkInfo() 定义为静态方法 public static ClerkInfo getClerkInfo() { return new ClerkInfo { name = "程饱饱", age = 25 }; } // 调用 updateClerkInfoName() 方法 c1.updateClerkInfoName("Choao"); Console.WriteLine(c1.name); // 调用 getClerkInfo() 方法 ClerkInfo clerk = ClerkInfo.getClerkInfo(); Console.WriteLine(clerk.name); Console.WriteLine(clerk.age);运行程序:
Choao Name: 程饱饱吃得好饱, Age: 24 程饱饱 256、结构的默认构造函数: 结构可以具有默认构造函数。如果没有定义任何构造函数,编译器将自动为结构生成一个默认的无参数构造函数,该构造函数将初始化结构的所有字段为其类型的默认值。
【示例完整代码展示】
namespace 结构的使用 { //结构放于此空间,所有类都可访问 public struct ClerkInfo { public string name; public int age; public string department; public char sex; public void PrintInfo() { Console.WriteLine("Name: {0}, Age: {1}", name, age); } //当作为参数传递时,会进行值的复制 public void updateClerkInfoName(string newName) { name = newName; } //当作为返回值返回时,会复制整个结构的值 // 将 getClerkInfo() 定义为静态方法 public static ClerkInfo getClerkInfo() { return new ClerkInfo { name = "程饱饱", age = 25 }; } } class Program { //如果放于此位置,只有当前Program类或继承类可以访问 static void Main(string[] args) { ClerkInfo c1 = new ClerkInfo(); c1.name = "Flyer"; c1.age = 24; c1.department = "数据库维护部"; c1.sex = '男'; Console.WriteLine("我是{0},{3}生,今年{1}岁,工作于{2}。", c1.name, c1.age, c1.department, c1.sex); // 调用 updateClerkInfoName() 方法 c1.updateClerkInfoName("Choao"); Console.WriteLine(c1.name); // 调用 PrintInfo() 方法 ClerkInfo c2 = new ClerkInfo { name = "程饱饱吃得好饱", age = 24 }; c2.PrintInfo(); // 调用 getClerkInfo() 方法 ClerkInfo clerk = ClerkInfo.getClerkInfo(); Console.WriteLine(clerk.name); Console.WriteLine(clerk.age); Console.ReadKey(); } } }运行程序:
我是Flyer,男生,今年24岁,工作于数据库维护部。 Choao Name: 程饱饱吃得好饱, Age: 24 程饱饱 25 9.2 枚举在C#中,枚举(Enumeration)允许定义一组命名常量。它们为常用的一组特定值提供了一个描述性的名称。枚举在代码中提高可读性,并使代码更易于理解。
【代码示例】
namespace 枚举 { //在此空间声明枚举,枚举作用与结构类似,可以在结构中被调用 public enum Gender { 男, 女 } public enum Week { 星期一,星期二,星期三,星期四,星期五,星期六,星期天 } class Program { static void Main(string[] args) { //枚举调用 Gender myGender = Gender.男; Week myWorkDay = Week.星期五; Console.WriteLine("我是{0}生,今天是{1}。",myGender,myWorkDay); //我是男生,今天是星期五。 //枚举中每个值会根据定义的顺序从0开始自动赋予每个值一个整型 //(int)实现将枚举转换为整型 Console.WriteLine((int)myGender); //0 Console.WriteLine((int)myWorkDay); //4 // Console.WriteLine(myGender.ToString()); //男 Console.WriteLine(myWorkDay.ToString()); //星期五 //将枚举转换为字符串 不能用(string) //只能用myWorkDay.ToString();或Convert.ToString(myWorkDay); Console.WriteLine(myGender); //男 Console.WriteLine(myWorkDay); //星期五 //(枚举名)实现将整型转换为枚举 int myInt = 5; Console.WriteLine((Week)myInt); //星期六 //将字符串转换为枚举值 string myStr = "星期五"; Console.WriteLine((Week)Enum.Parse(typeof(Week), myStr)); //星期五 Console.ReadKey(); } } }Note: 当枚举值没有明确赋值时,默认从0开始自增,所以 星期一 的值为0,星期二 的值为1,依此类推。
枚举是用于表示一组有限的可能性的强类型标识符。
9.3 面向对象概述C# 是一种面向对象的编程语言,它支持面向对象编程(OOP)的核心原则和概念。面向对象编程是一种用于构建软件系统的编程范式,它将现实世界中的问题分解为一组相关的对象,并通过对象之间的交互来解决这些问题。
以下是面向对象编程的一些核心概念和特性:
1、类(Class): 类是面向对象编程的基本构建块,它是对象的蓝图或模板。类定义了对象的属性(字段)和行为(方法)。
2、对象(Object): 对象是类的实例化,它是类定义的具体实体,具有特定的状态和行为。通过创建对象,我们可以使用类定义的属性和方法。
3、封装(Encapsulation): 封装是面向对象的一个重要概念,它将数据和方法封装在类中,并通过公共接口提供对它们的访问。封装隐藏了内部实现的细节,使对象的使用者只需关注公共接口。
4、继承(Inheritance): 继承允许一个类(子类)从另一个类(父类)继承属性和方法。子类可以扩展父类的功能,并添加自己的特定行为。继承实现了代码的重用和层次结构的建立。
5、多态(Polymorphism): 多态允许对象在不同的上下文中表现出不同的行为。通过多态,父类的引用可以指向子类的对象,使得在调用相同的方法时可以产生不同的结果。
9.4 类与对象的关系类和对象是面向对象编程中两个重要的概念,它们之间存在着紧密的关系。
类(Class): 类是面向对象编程的基本构建块,它是对象的模板或蓝图,用于定义对象的属性(字段)和行为(方法)。类可以看作是一类对象的抽象表示,描述了对象的共同特性。 对象(Object): 对象是类的实例化,它是类的具体实体,具有特定的状态和行为。通过创建对象,可以使用类定义的属性和方法。
类与对象之间的关系如下:
类是对象的抽象,表示一类相似对象的定义。它描述了对象所具有的属性和方法,并提供了创建对象的模板。 对象是类的具体实例,它根据类的定义创建,并具有类所定义的属性和方法。可以通过关键字 new 来创建类的实例。 类是对象的定义;对象是类的实例。 类定义了对象的结构和行为,包括属性和方法等;而对象持有类定义的属性值和对方法的调用。
【示例代码】
class Car { public string brand; public string color; public void Start() { Console.WriteLine("The car starts."); } public void Accelerate() { Console.WriteLine("The car accelerates."); } } class Program { static void Main(string[] args) { // 创建一个Car类的对象 Car myCar = new Car(); // 设置对象的属性值 myCar.brand = "Toyota"; myCar.color = "Red"; // 调用对象的方法 myCar.Start(); myCar.Accelerate(); Console.ReadKey(); } }在上述代码中,定义了一个名为 Car 的类,它具有 brand 和 color 属性以及 Start( ) 和 Accelerate( ) 方法。在 Main 方法中,我们创建了一个 Car 类的对象 myCar,并设置了其品牌和颜色属性的值。然后,我们通过 myCar 对象调用了 Start( ) 和 Accelerate( ) 方法。
通过类和对象的关系,我们可以实现代码的封装性、复用性和可维护性。类定义了对象的结构和行为,而对象则代表了类的实例,具有类所定义的属性和方法。
9.5 类的声明定义类的方式: 右击需要创建类的所在解决方案下的项目 --> 添加 --> 类 --> 命名、添加 完成后会打开一个新的页面,定义完成后保存,可返回Main方法中调用。
【类的声明】
public enum Gender { 男,女 } class Clerk { //定义字段,字段可以存放多个值命名规范:_camelCase,变量只能放一个值 public string _name; public Gender _gender; public int _age; public string _department; public int _workYears; //定义一个非静态方法 public void Print() { Console.WriteLine("我叫{0},{1}生,今年{2}岁,在{3}部门工作{4}年了。",this._name, this._gender, this._age, this._department, this._workYears); } }【类的调用】
static void Main(string[] args) { //调用类需将类实例化 实例化:将类指定个某个对象 Clerk c1 = new Clerk(); Clerk c2 = new Clerk(); //c1对象赋值 c1._name = "Flyer.Cheng"; c1._gender = Gender.男; c1._age = 24; c1._department = "数据库维护"; c1._workYears = 2; //调用非静态方法 c1.Print(); //c2对象赋值 c2._name = "Anna.Wang"; c2._gender = Gender.女; c2._age = 25; c2._department = "财务"; c2._workYears = 3; //调用非静态方法 c2.Print(); //声明一个变量 string myStr = "程饱饱"; Console.WriteLine(c1._name); Console.WriteLine(c2._name); //_name同一个字段 不同对象 Console.WriteLine(myStr); Console.WriteLine(myStr); //说明字段中可以存储多个值,而变量中只能存一个值 Console.ReadKey(); }运行程序:
我叫Flyer.Cheng,男生,今年24岁,在数据库维护部门工作2年了。 我叫Anna.Wang,女生,今年25岁,在财务部门工作3年了。 Flyer.Cheng Anna.Wang 程饱饱 程饱饱 9.6 属性的使用 9.6.1 属性在C#中,属性(Properties)是一种特殊的成员,用于封装类的字段,以提供对字段的安全访问和控制。属性允许读取和写入私有字段的值,并提供了对字段的验证和计算的机会。
属性具有类似字段的语法,但在背后使用了get和set访问器来实现对字段的访问和修改。通过属性,可以隐藏实际的字段,并在访问和修改字段时执行额外的逻辑。
以下是使用属性的基本语法:
访问修饰符 数据类型 属性名 { get { return 字段名; } set { 字段名 = value; } } 访问修饰符:指定属性的可访问性,可以是public、private等。数据类型:指定属性的数据类型,例如int、string等。属性名:给属性命名的标识符,按照命名约定应使用PascalCase(首字母大写)。get访问器:用于获取属性的值。它是一个返回属性类型的代码块。set访问器:用于设置属性的值。它是一个接受属性类型的参数的代码块。以下是一个简单的使用属性的示例:
class Person { private string name; // 私有字段 public string Name // 公共属性 { get { return name; } set { name = value; } } }在上述的示例中,我们定义了一个名为Person的类,其中有一个私有字段 name 和一个公共属性 Name。属性Name提供了对字段name的访问和修改。
使用属性:
Person person = new Person(); person.Name = "flyer"; // 设置属性的值 string name = person.Name; // 获取属性的值通过属性,可以对字段的值进行控制和验证,可以在set访问器中加入一些逻辑,以确保赋给属性的值满足一定的条件。以下是一个使用属性验证的示例:
class Person { private string name; // 私有字段 public string Name // 公共属性 { get { return name; } set { if (value != null && value.Length > 0) { name = value; } } } }在上述示例中,添加了对属性 Name赋值的验证逻辑。只有当赋给属性的值不为空且长度大于0时,才赋给字段 name。
属性还可以使用自动实现的方式来减少代码量。通过自动实现属性,不需要手动编写get和set访问器,编译器会自动生成默认的访问器。
以下是使用自动实现属性的示例:
class Person { public string Name { get; set; } // 自动实现属性 }在上述代码中,使用简化的语法声明了一个自动属性 Name 。编译器会自动创建一个名为 Name 的私有字段,并使用 get 和 set 访问器对属性的值进行读取和写入。
9.6.2 属性使用1、属性的声明: C#中属性的声明类似于方法的声明,但使用 get 和 set 访问器来定义属性的读取和写入行为。属性通常与一个私有字段相关联,以存储属性的值。
public int MyProperty { get { return myField; } // 获取属性值并返回 set { myField = value; } // 设置属性值 }在上述代码中,声明了一个名为 MyProperty 的属性,它与一个名为 myField 的私有字段相关联。通过 get 访问器,返回字段的值,通过 set 访问器,设置字段的值。
2、自动属性: C#中还提供了自动属性的简化语法,可以极大地简化属性的声明。自动属性会自动创建一个隐藏的私有字段,用于存储属性的值。下面是自动属性的示例:
public int MyProperty { get; set; }在上述代码中,使用简化的语法声明了一个自动属性 MyProperty。编译器会自动创建一个名为 MyProperty 的私有字段,并使用 get 和 set 访问器对属性的值进行读取和写入。
使用自动属性时,可以提供简洁性和可读性;但是如果需要在获取或设置属性值时执行其他逻辑,还是需要使用完整的属性声明。
3、只读属性: 如果只需要创建一个只读属性,即只有 get 访问器而没有 set 访问器,可以省略 set 访问器。只读属性只能在构造函数或属性的初始值设定项中设置值。
public int MyReadOnlyProperty { get; }在上述代码中,声明了一个只读属性 MyReadOnlyProperty,只有 get 访问器。这意味着可以通过 get 访问器读取属性的值,但无法通过 set 访问器设置属性的值。
4、访问属性:
// 创建类的实例 MyClass obj = new MyClass(); // 设置属性的值 obj.MyProperty = 10; // 获取属性的值 int value = obj.MyProperty;在上述代码中,创建了一个类的实例 obj。通过 obj 对象,我们可以使用点运算符 . 来访问和设置属性的值。
Note: ① 属性由 get 和 set 访问器组成,用于读取和写入属性的值。 ② 访问器可以定义为 public、private、protected 或 internal 等修饰符,用于控制对属性的访问级别。
【综合代码示例】
1、Clerk类的定义:
class Clerk { //类中可以存放: //字段:采用_camelCase命名方式 //属性:采用PascaCase命名方式 //方法: //定义属性后往往都会通过属性来访问字段 //通常情况下 属性声明为public 字段声明为private //在外部访问类中的字段都是通过属性实现 public string _name; public string Name { get; set; //自动属性进行预留,以防后期需要添加限定 } public char _gender; //定义属性Gender //通常我们将get与set称为访问器,有四种: //1>既读又写 同时包含get和set //2>只读 只包含get //3>只写 只包含set //4>自动 get public char Gender { get //get可以对取值进行限定 { if (_gender != '女' && _gender != '男') _gender = 'N'; return _gender; } set //set可以对赋值进行限定 { _gender = value; } } public int _age; //定义属性Age public int Age { get //get可以对取值进行限定 { return _age; } set //set可以对赋值进行限定 { if (value < 0 || value > 120) value = 0; _age = value; } } public string _department; public string Department { get; set; //自动属性进行预留,以防后期需要添加限定 } public int _workYears; public int WorkYears { get; set; //自动属性进行预留,以防后期需要添加限定 } public void Print() { Console.WriteLine("我叫{0},{1}生,今年{2}岁,我已经在{3}工作{4}年了。", this.Name, this.Gender, this.Age, this.Department, this.WorkYears); //this关键字表示当前类对象 } }2、主体方法调用类:
class Program { static void Main(string[] args) { //将类实例化后分别赋值,调用方法 Clerk c1 = new Clerk(); //直接调用 c1.Name = "程饱饱"; c1.Gender = '男'; c1.Age = 24; c1.Department = "数据库开发维护部"; c1.WorkYears = 2; c1.Print(); //通过属性调用 Console.WriteLine("通过属性访问字段:Gender:{0},Age:{1}。",c1.Gender,c1.Age); Console.ReadKey(); } } 9.7 构造函数和析构函数 9.7.1 构造函数构造函数是用于初始化对象的特殊方法,它有以下特性: ① 它在创建对象时自动调用,并用于设置对象的初始状态。 ② 名称与类的名称相同,并且没有返回类型。 ③ 可以具有参数(参数化构造函数),用于在创建对象时传递参数。 ④ 参数化构造函数可以接受不同类型和数量的参数。 ⑤ 构造函数支持重载。
【示例代码】
1、类和方法的定义
public enum Gender { 男,女 } class Clerk { private string _name; public string Name { get { return _name; } set { _name = value; } } private Gender _gender; public Gender Gender { get{ return _gender; } set{ _gender = value; } } private int _age; public int Age { get{return _age;} set{_age = value;} } private string _department; public string Department { get { return _department; } set { _department = value; } } private int _workYears; public int WorkYears { get { return _workYears; } set { _workYears = value; } } public void Print() { Console.WriteLine("我叫{0},{1}生,今年{2}岁,我已经在{3}工作{4}年了。", this.Name, this.Gender, this.Age, this.Department, this.WorkYears); } //构造函数:是一种特殊的方法,没有返回值但是不能使用void,必须public,且构造函数的名称必须跟类名一致 public Clerk(string name,Gender gender,int age,string department,int workYears) { this.Name = name; this.Gender = gender; this.Age = age; this.Department = department; this.WorkYears = workYears; } }2、主体方法的调用 ① 如果没有定义构造函数Clerk,需要实例化类然后赋值并调用:
class Program { static void Main(string[] args) { Clerk c1 = new Clerk(); c1.Name = "程饱饱"; c1.Gender = Gender.男; c1.Age = 24; c1.Department = "数据库维护开发部"; c1.WorkYears = 2; c1.Print(); Console.ReadKey(); } } 我叫程饱饱,男生,今年24岁,我已经在数据库维护开发部工作2年了。② 定义构造函数Clerk后,可简化实例化及赋值代码:
class Program { static void Main(string[] args) { Clerk c1 = new Clerk("程饱饱",Gender.男,24, "数据库维护开发部",2); c1.Print(); Console.ReadKey(); } } 我叫程饱饱,男生,今年24岁,我已经在数据库维护开发部工作2年了。new 关键字: 1)在内存中开辟空间 2)在开辟空间中创建对象 3)对对象进行初始化,将各个属性值赋值
在创建类中会存在一个默认的无参数的构造函数,一旦定义了新的构造函数,不论新的构造函数是否有有参数,原默认的无参数的构造函数都会被覆盖掉。
9.7.2 析构函数析构函数 是在销毁对象时自动调用的特殊方法: ① 它的名称与类的名称相同,但在方法名前加上一个波浪号(~)。 ② 析构函数没有参数,没有访问修饰符和返回类型。 ③ 析构函数不需要手动调用,CLR(Common Language Runtime)会自动在对象销毁时调用析构函数。 ④ 析构函数常用于执行一些清理操作,例如释放非托管资源、关闭文件、释放数据库连接等。
需要注意: C#中的析构函数不像其他语言(如C++)那样可靠,无法保证准确的释放资源。因此,在C#中常用的是使用 Dispose( ) 方法和 using 语句来释放资源。
以下是析构函数的基本语法:
public class MyClass { ~MyClass() // 析构函数的声明 { // 析构函数的代码 } }关于析构函数: 1、析构函数的执行时机: ① 析构函数在对象被销毁时自动调用,也就是当对象的生命周期结束时(例如,对象离开作用域、对象被赋予其他引用、程序终止等)。 ② 析构函数不能被显式调用,也不能手动触发对象的销毁。
2、析构函数的清理操作: ① 析构函数主要用于执行清理操作,例如释放非托管资源(如文件、数据库连接等)或其他资源的释放和关闭。 ② 在析构函数中可以使用任何合法的C#代码,具体的清理操作根据需求来决定。
3、析构函数的注意事项: ① 析构函数通常用于释放非托管资源。对于托管资源(例如,使用垃圾回收管理的资源),不需要在析构函数中进行额外的处理,因为垃圾回收器会自动释放托管资源。 ② 由于析构函数的执行时间是无法确定的,不要在析构函数中依赖于外部资源或其他对象的状态。 析构函数不能被继承、重载或显式调用。 ③ 一个类只能有一个析构函数。
4、垃圾回收器(Garbage Collector)和析构函数: ① 垃圾回收器负责管理和释放托管内存,它会自动回收不再使用的对象以释放内存空间。 ② 与垃圾回收器不同,析构函数主要用于释放非托管资源,并在对象销毁时执行其他清理操作(如关闭文件、释放数据库连接)。
9.8 类的继承面向对象编程(Object-oriented programming)的三个基本特征是封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。
9.9 类的封装面向对象编程(Object-oriented programming)的三个基本特征是封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。
9.10 类的多态面向对象编程(Object-oriented programming)的三个基本特征是封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。
C#学习笔记-C#基础知识-C#从入门到放弃-C#结构、类与属性由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C#学习笔记-C#基础知识-C#从入门到放弃-C#结构、类与属性”