《C#图解教程》拾遗十一-结构

目录

一、什么是结构

二、结构是值类型

三、对结构赋值

四、构造函数和析构函数

1、实例构造函数

2、静态构造函数

3、构造函数和析构函数小结

五、属性和字段初始化语句

六、结构是密封的

七、装箱和拆箱

八、结构作为返回值和参数

九、关于结构的更多内容


一、什么是结构

结构是程序员定义的数据类型,与类非常类似,它们有数据成员和函数成员,虽然与类相似,但是结构有许多重要的区别,最重要的区别是:

  • 类是引用类型,而结构是值类型;
  • 结构是隐式密封的,这意味着不能从它们派生其他结构;

声明结构的语法与声明类相似:

关键字
  ⬇
struct StructName
{
    MemberDeclarations
}
struct Point
{
    public int X;
    public int Y;
}
class Program
{
    static void Main(string[] args)
    {
        Point first, second, third;

        first.X = 10;first.Y = 10;
        second.X = 20;second.Y = 20;
        third.X = first.X + second.X;
        third.Y = first.Y + second.Y;

        Console.WriteLine($"first: {first.X},{first.Y}");
        Console.WriteLine($"second: {second.X},{second.Y}");
        Console.WriteLine($"third: {third.X},{third.Y}");
    }
}

执行结果:

二、结构是值类型

和所有值类型一样,结构类型变量含有自己的数据,因此:

  • 结构类型的变量不能为null;
  • 两个结构变量不能引用同一对象;
class CSimple
{
    public int X;
    public int Y;
}
struct Simple
{
    public int X;
    public int Y;
}
class Program
{
    static void Main()
    {
        CSimple cs = new CSimple();
        Simple ss = new Simple();
        ...
    }
}

上述代码声明了一个名为CSimple的类和一个名为Simple的结构,当为它们各自声明一个变量时,下图展示了这两个变量的内存安排:

三、对结构赋值

把一个结构赋值给另一个结构,就是将一个结构的值复制给另一个结构,这和复制类变量不同,复制类变量时只复制引用。

class CSimple
{
    public int X;
    public int Y;
}
struct Simple
{
    public int X;
    public int Y;
}
class _3_AssignValueToStruct
{
    static void Main()
    {
        CSimple cs1 = new CSimple(), cs2 = null;            //类实例
        Simple ss1 = new Simple(), ss2 = new Simple();      //结构实例

        cs1.X = ss1.X = 5;          //将5赋值给ss1.X和cs1.X
        cs1.Y = ss1.Y = 10;         //将10赋值给ss1.Y和cs1.Y

        cs2 = cs1;                  //赋值类实例
        ss2 = ss1;                  //赋值结构实例
    }
}

上图展示了类变量赋值和结构变量赋值的区别。

注意,在类赋值之后,cs2和cs1指向堆中同一对象,但在结构赋值之后,ss2的成员的值和ss1的相同。

四、构造函数和析构函数

结构可以有实例构造函数和静态构造函数,但不允许有析构函数。

1、实例构造函数

语言隐式地为每个结构提供一个无参数的构造函数,这个构造函数把结构的每个成员设置为该类型的默认值,值成员设置成它们地默认值,引用成员设置成null。

对于每个结构,都存在预定义的无参构造函数,而且不能删除或重定义。但是,可以创建另外的构造函数,只要它们有参数。注意,这和类不同,对于类,编译器只在没有声明其他构造函数时提供隐式的无参构造函数。

调用一个构造函数,包括饮食无参数构造函数,要使用new运算符,注意,即使不从堆中分配内存,也要使用new运算符。

struct Simple
{
    public int X;
    public int Y;
    public Simple(int a,int b)      //带有参数的构造函数
    {
        X = a;
        Y = b;
    }
}
class _4_1InstantConstructure
{
    static void Main()
    {
        Simple s1 = new Simple();           //调用隐式构造函数
        Simple s2 = new Simple(5, 10);      //调用构造函数

        Console.WriteLine($"{s1.X},{s1.Y}");
        Console.WriteLine($"{s2.X},{s2.Y}");
    }
}

也可以不适用new运算符创建结构的实例,然而,如果这样做,有如下限制:

  • 在显式设置数据成员之后,才能使用它们的值;
  • 在对所有数据成员赋值之后,才能调用结构的函数成员;
struct Simple
{
    public int X;
    public int Y;
}
class _4_12InstantConstructure
{
    static void Main()
    {
        Simple s1, s2;  //没有构造函数的调用
        //Console.WriteLine("{0},{1}", s1.X, s1.Y);   //还未被赋值,编译错误,使用了可能未赋值的字段

        s2.X = 5;
        s2.Y = 10;
        Console.WriteLine($"{s2.X},{s2.Y}");    //没问题
    }
}

2、静态构造函数

与类相似,结构的静态构造函数创建并初始化静态数据成员,并且不能引用实例成员。结构的静态构造函数遵从与类的静态构造函数一样的规则,但允许有不带参数的静态构造函数。

以下两种行为,任意一种发生之前,将会调用静态构造函数:

  • 调用显式声明的构造函数;
  • 引用结构的静态成员;

3、构造函数和析构函数小结

五、属性和字段初始化语句

在声明结构体时,不允许使用实例属性和字段初始化语句:

struct Simple
{
    public int x = 0;    //编译错误
    public int y = 10;   //编译错误

    public int prop1 {get; set;} = 5;    //编译错误
}

但是,结构体的静态属性和静态字段都可以在声明结构体时进行初始化,即使结构体本身不是静态的。

六、结构是密封的

结构总是隐式密封的,因此,不能从它们派生其他结构。

由于结构不支持继承,个别类成员修饰符用在结构成员上将没有意义,因此不能在结构成员声明中使用。不能用于结构的修饰符如下:

  • protected
  • protected internal
  • abstract
  • sealed
  • virtual

结构本身派生自System.ValueType,而System.ValueType派生自object。

两个可用于结构成员并与继承相关的关键字是new和override修饰符,当创建一个和基类System.ValueType的成员同名的成员时可使用它们,所有结构都派生自System.ValueType。

七、装箱和拆箱

如同其他值类型数据,如果想将一个结构实例作为引用类型对象,必须创建装箱的副本。装箱的过程就是制作值类型变量的引用类型副本。

八、结构作为返回值和参数

结构可以用作返回值和参数:

  • 返回值        当结构作为返回值时,将创建它的副本并从函数成员返回;
  • 值参数        当结构被用作值参数时,将创建实参结构的副本,该副本用于方法的执行中;
  • ref和out参数        如果把一个结构用作ref或out参数,传入方法的是该结构的一个引用,这样就可以修改其数据成员;

九、关于结构的更多内容

对结构进行分配的开销比创建类实例小,所以使用结构代替类有时可以提高性能,但要注意装箱和拆箱的高昂代价。

关于结构,需要知道的最后一些事情如下:

  • 预定义简单类型(int、short、long等)尽管在.net和C#中被视为原始类型,但它们实际上在.net中都实现为结构;
  • 可以使用与声明分部类相同的方法声明分部结构;
  • 结构和类一样,可以实现接口;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《轻松学C#(图解版)》完整扫描版================================================================ 基本信息 作者:谷涛、扶晓、毕国锋 丛书名:轻松学开发 出版社:电子工业出版社 ISBN:978-7-121-20223-0 出版日期:2013年6月 开本:16开 页码:408页 版次:1-1 定价:¥55.00 所属分:计算机 > 软件与程序设计 > C# ================================================================ 内容简介 本书由浅入深,全面、系统地介绍了C#程序设计。除了详细地讲解C#知识点外,本书还提供了大量的实例,供读者实战演练。本书共分三篇。第一篇是C#概述篇,主要介绍的是Visual Studio 2012的开发环境及搭建。第二篇是面向对象基础篇,主要介绍、对象、字段、方法、流程控制、数组、继承、属性、运算符重载、接口等C#基本内容。第三篇是应用技术篇,主要介绍的是异常处理、文件和流、委托、事件、Lambda表达式、命名空间、预处理器、程序集、运行时型标识、反射、特性、泛型、LINQ和数据库开发等。 ================================================================ 图书目录 第一篇 C#概述篇 第1章 C#入门 2 1.1 C#概述 2 1.1.1 C#的发展 2 1.1.2 C#开发的基础 2 1.2 搭建开发环境 3 1.2.1 Visual Studio 2012软硬件配置要求 3 1.2.2 下载Visual Studio 2012 3 1.2.3 安装Visual Studio 2012 4 1.2.4 初始化配置 7 1.3 第一个程序—Hello World 8 1.4 小结 11 1.5 习题 12 第二篇 面向对象基础篇 第2章 和对象 16 2.1 分析Hello World程序 16 2.2 语法规范 17 2.2.1 标识符 17 2.2.2 关键字 18 2.2.3 注释 19 2.3 定义 20 2.4 实例化对象 20 2.5 小结 20 2.6 习题 21 第3章 定义——字段 23 3.1 数据型 23 3.1.1 简单值型 23 3.1.2 值的表示——字面量 26 3.1.3 转义序列 27 3.2 定义字段 27 3.2.1 定义字段 28 3.2.2 静态字段和实例字段的访问 28 3.2.3 字段初始化 29 3.2.4 字段的动态赋值——Read()和ReadLine() 31 3.2.5 字段输出 31 3.2.6 格式化输出 32 3.2.7 数据型转换 39 3.2.8 只读字段 41 3.2.9 访问控制 41 3.3 运算符 43 3.3.1 算术运算符 43 3.3.2 自增、自减运算符 44 3.3.3 复合赋值运算符 45 3.3.4 位运算符 46 3.3.5 sizeof运算符 47 3.3.6 运算符的优先级 47 3.4 小结 49 3.5 习题 49 第4章 定义——方法 51 4.1 方法的概述 51 4.1.1 定义方法 51 4.1.2 方法的调用 52 4.2 方法体的构成 53 4.2.1 局部变量 53 4.2.2 局部变量与字段同名的解决——this关键字 54 4.2.3 语句 55 4.2.4 全局变量 55 4.3 返回值 56 4.3.1 返回值型 56 4.3.2 从方法返回 57 4.4 参数 58 4.4.1 参数的分 58 4.4.2 引用参数(ref参数) 59 4.4.3 输出参数(out参数) 61 4.5 特殊的方法 62 4.5

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值