【概述】
C#中结构类型和类类型在语法上非常相似,他们都是一种数据结构,都可以包括数据成员和方法成员。结构体是值类型,直接包含它自己的数据,每个结构都保存自己的一份数据,修改每一个结构的数据都不会对其他结构的数据造成影响。
注意:
struct关键字修饰。
【结构体声明方式】
权限访问修饰符 struct 结构体类型名{
/*结构体成员*/
/*
字段、
属性、
方法、
……
*/
}
eg:
// #region << 版 本 注 释 >>
// /*----------------------------------------------------------------
// // Copyright (C) 2019 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
namespace MSN
{
public struct PersonStruct
{
public string Name;
public string MobilePhone;
public DateTime Birthday;
}
class MainClass
{
public static void Main(string[] args){
PersonStruct p1, p2; //与类一样,但可以不new
p1.Name = "张飞";
p1.MobilePhone = "13553663108";
p1.Birthday = DateTime.Now.AddYears(-10);
p2 = p1; //将p1的值赋给p2
//由于是值类型,因此赋值等于将全部值全部复制到p2的栈空间
p2.Name = "关羽"; //修改p2的值看是否会影响p1
Console.WriteLine(p1.Name); //输出 张飞 没影响•
}
}
}
注意:
将一个结构变量赋值给另一个结构变量,就是把数据从一个结构复制到另一个结构。
【结构体构造函数与析构函数】
结构类型可以有实例构造函数和静态构造函数,但不能有析构函数。
【结构体实例构造函数】
结构体类型都有一个预定义的,没有参数的构造函数。此构造函数不允许删除和重定义,并且这个无参数的构造函数会一直存在,并不会因为定义了其他带参数的构造函数就消失。
注意:
- 如果没有使用new运算符,是不可以使用数据成员的值(除非已显示地设置了该数据成员的值)和调用函数成员(除非所有数据成员均已经被赋值)。
- 定义结构体构造函数时,也需要对所有的数据成员进行初始化。
eg:
// #region << 版 本 注 释 >>
// /*----------------------------------------------------------------
// // Copyright (C) 2019 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
namespace MSN
{
public struct PersonStruct
{
public string Name;
public string MobilePhone;
public DateTime Birthday;
/*实例构造函数*/
public PersonStruct(string _name, string _mp, DateTime _dt) {
this.Name = _name;
this.MobilePhone = _mp;
this.Birthday = _dt;
}
public void Show() {
Console.WriteLine("PersonStruct.Name = {0}, " +
"PersonStruct.MobilePhone = {1}," +
"PersonStruct.Birthday = {2}",
this.Name, this.MobilePhone, this.Birthday);
}
public override string ToString()
{
return string.Format("PersonStruct.Name = {0}, " +
"PersonStruct.MobilePhone = {1}," +
"PersonStruct.Birthday = {2}", this.Name,
this.MobilePhone, this.Birthday);
}
}
class MainClass
{
public static void Main(string[] args){
PersonStruct p1; //与类一样,但可以不new••
p1.Name = "张飞";
p1.MobilePhone = "13553663108";
p1.Birthday = DateTime.Now.AddYears(-10);
p1.Show();
PersonStruct p2 = new PersonStruct("李云龙", "13315378765", DateTime.Now.AddYears(10));
Console.WriteLine(p2.ToString());
}
}
}
【结构体静态构造函数】
结构体类型也可以有静态构造函数,静态构造函数用于初始化静态数据成员。静态构造函数有如下特点:
1:静态构造函数不能使用任何访问修饰符
2:静态构造函数不能带有任何参数
3:静态构造函数只会执行一次
4:不能直接调用静态构造函数
5:程序员无法直接控制静态构造函数调用时机
6:静态构造函数不能访问实例成员
结构体的静态构造函数的触发规则:
1、使用显式声明的构造函数进行初始化,使用默认的构造函数进行初始化不会触发。
2、调用结构体的方法或访问结构体的静态数据成员(无论是读取还是赋值,访问实例数据成员不会触发CLR自动调用静态的构造函数)。
eg:
// #region << 版 本 注 释 >>
// /*----------------------------------------------------------------
// // Copyright (C) 2019 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
namespace MSN
{
public struct PersonStruct
{
//实例成员变量
public string Name;
public string MobilePhone;
public DateTime Birthday;
//静态成员变量
public static int s_iNum = 100;
/*实例构造函数*/
public PersonStruct(string _name, string _mp, DateTime _dt) {
this.Name = _name;
this.MobilePhone = _mp;
this.Birthday = _dt;
}
/*静态构造函数*/
static PersonStruct() {
//this.Name = "林耀东";//❌静态构造函数不能访问实例成员;
s_iNum++;//静态成员变量
Console.WriteLine("Static Constructor Function of PersonStruct");
}
//实例成员函数
public void Show() {
Console.WriteLine("PersonStruct.Name = {0}, " +
"PersonStruct.MobilePhone = {1}," +
"PersonStruct.Birthday = {2}",
this.Name, this.MobilePhone, this.Birthday);
}
public static void SPrint() {
Console.WriteLine("s_iNum = {0}", s_iNum);
}
//函数重写
public override string ToString()
{
return string.Format("PersonStruct.Name = {0}, " +
"PersonStruct.MobilePhone = {1}," +
"PersonStruct.Birthday = {2}", this.Name,
this.MobilePhone, this.Birthday);
}
}
class MainClass
{
public static void Main(string[] args){
/*使用显式声明的构造函数进行初始化,使用默认的构造函数进行初始化不会触发。*/
PersonStruct p1 = new PersonStruct();
PersonStruct p2 = new PersonStruct("李云龙", "13315378765", DateTime.Now.AddYears(10));•
Console.WriteLine(p2.ToString());
/*调用结构体的方法或访问结构体的静态数据成员(无论是读取还是赋值,访问实例数据成员不会触发CLR自动调用静态的构造函数)。*/
Console.WriteLine("s_iNum = {0}", PersonStruct.s_iNum);
PersonStruct.SPrint();
}
}
}
【结构体继承性和多态性】
结构体直接派生自System.ValueType,间接派生自System.Object,但结构体是隐式密封的,不能作为基类再派生出其他的结构。
结构的特性:
1、结构类型总是隐式密封的,因此在定义结构时不能使用sealed和abstract关键字;
2、因为结构不能作为基类,结构的成员不能使用如下访问修饰符:protected和protected internal;
3、结构的函数成员不能声明为abstract和virtual,但是可以使用override关键字,用以覆写它的基类System.ValueType中的方法。
9.2 运算符重载
C#里面也有运算符重载,主要是为了对自定义的类型使用某一个运算符。对于一元运算符,重载需要带一个类或结构类型作为参数;而二元运算符重载则需要带两个类或该类型的结构体。语法如下:
public static 类型 operator 重载的运算符(类型1,类型2)
从中可以看出,所有的运算符都应该为静态方法,且需要使用public关键字进行修饰。
// #region << 版 本 注 释 >>
// /*----------------------------------------------------------------
// // Copyright (C) 2019 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
namespace MSN
{
public struct Complex
{
public int real;
public int imaginary;
public Complex(int r, int c)
{
this.real = r;
this.imaginary = c;
}
public static Complex operator +(Complex c1, Complex c2)
{
Complex result = new Complex();
result.real = c1.real + c2.real;
result.imaginary = c1.imaginary + c2.imaginary;
return result;
}
public override string ToString()
{
return string.Format("{0}+{1}i", real, imaginary);
}
}
class MainClass
{
public static void Main(string[] args){
Complex num1 = new Complex(2, 4);
Complex num2 = new Complex(3, 6);
Complex sum = num1 + num2;
Console.WriteLine("两个复数和为{0}", sum);
}
}
}