02010401 类型、存储和变量

02010401 类型、存储和变量

1. 什么是类型

  • C#程序是一组类型声明。
    • C#程序或DLL的源代码是一组类型声明。
    • 对于可执行程序,类型声明中必须有一个包含Main方法的类。
    • 命名空间是一种将相关的类型声明分组并命名的方法,因为程序是一组相关的类型声明,所以通常在你创建的命名空间内部声明程序类型。
  • 学习C#就是学习如何创建和使用类型,可以把类型想象成一个用来创建数据结构的模板。类型由如下元素定义:
    • 名称
    • 用来保存数据成员的数据结构
    • 一些行为及约束条件

2. 实例化类型

  • 从某个类型模板创建实际的对象,成为实例化该类型,通过实例化类型而创建的对象被称为类型的对象(类型的实例)。
  • 在C#程序中,每个数据项都是某种类型的实例。这些类型可以是语言自带的,可以是BCL或其它库提供的,也可以是程序员自定义的。

3. 数据成员和函数成员

  • 像short,int和long这样的类型称为简单类型,这种类型只能存储一个数据项。

  • 其它的类型可以存储多个数据项,比如数组类型就可以存储多个同类型的数据项,这些数据项称为数组元素。

  • 类型有两种成员:数据成员和函数成员。

    • 数据成员 -> 保存了与这个类的对象或整个类相关的数据。
    • 函数成员 -> 执行代码,定义类型的行为。
class MyClass
{
    // 数据成员
    int a;
    string b;
    
    // 函数成员
    void Func01()
    {
    }
    
    int Func02()
    {
    }
}

说明:上述代码段包含2个数据成员和两个函数成员。

4. 预定义类型

  • C#提供了16种预定义类型,其中包含13种简单类型和3种非简单类型,所有预定义类型的名称全都由全小写的子母组成。
  • 简单类型13种
    • 11种数值类型
      • 不同长度的有符号和无符号整数类型stybe,byte,short,ushort,int,uint,long,ulong
      • 浮点数类型float和double
      • 一种称为decimal的高精度小数类型,该类型可以表示分数,常用于货币的计算。
    • 一种Unicode字符类型char
    • 一种布尔类型bool,该类型表示布尔值并且必须为true或false。
  • 非简单类型3种
    • string,它是一个Unicode字符数组
    • object,它是所有其它类型的基类
    • dynamic,使用动态语言编写程序集时使用。

5. 用户定义类型

  • 除了C#提供的16种预定义类型,还可以创建自己的用户类型。有6种类型可以由用户自己创建

    • 类类型(class)
    • 结构类型(struct)
    • 数组类型(array)
    • 枚举类型(enum)
    • 委托类型(delegate)
    • 接口类型(interface)
  • 类型通过类型声明创建,类型声明包含如下信息

    • 要创建的类型的种类
    • 新类型的名称
    • 对类型中每个成员的声明(array和delegate类型除外,他们不还有命名成员)
  • 用户一旦声明了类型,就可以创建和使用这种类型的对象。

// 预定义类型和实例化预定义类型对象
预定义类型                   实例化对象
int                        int a
float                      float b
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 用户定义类型和实例化用户定义类型对象
用户定义类型                 实例化对象
class A                    A a
class B                    B b
struct Def                 Def def
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:
1. 预定义类型只需要进行实例化
2. 用户定义类型需要先声明类型,再实例化。

6. 栈和堆

6.1 栈
图片链接丢失
  • 栈是一个内存数组,是一个LIFO(Last-In,First-Out,后进先出)的数据结构,栈存储如下几种类型的数据:
    • 某些类型变量的值
    • 程序当前的执行环境
    • 传递给方法的参数
  • 栈的特征,为了便于理解可以将栈视为一个弹夹。
    • 数据只能从栈的顶端插入和删除
    • 把数据放到栈顶称为入栈(push)
    • 从栈顶删除数据称为出栈(pop)
6.2 堆
图片链接丢失
  • 堆是一块内存区域,在堆里可以分配大块的内存用于存储某种类型的数据对象。与栈不同,堆里的内存能够以任意顺序存入和移除。

  • 虽然程序可以在堆里保存数据,但并不能显示的删除它们。CLR的自动垃圾收集器在判断出程序的代码不会再访问某项数据时,会自动清除无主的堆对象。

7. 值类型和引用类型

图片链接丢失
  • 数据项的类型定义了存储数据需要的内存大小及组成该类型的数据成员,类型还决定了对象在内存中的存储位置——栈或堆。
  • 类型被分为2种:值类型和引用类型。这2种类型的对象在内存中的存储方式不同。
    • 值类型 -> 只需要一段单独的内存,用于存储实际的数据。

      • 值类型数据存放在栈里。
    • 引用类型 -> 需要2段内存。

      • 第1段存储实际的数据,它总是位于堆中
      • 第2段是一个引用,指向数据在堆中的存放位置
      • 引用类型实际数据存放在堆里,而引用存放在栈里。

8. 存储引用类型对象的成员

  • 假设有一个引用类型(MyType)的实例(myType),它有两个成员:一个是值类型成员,一个是引用类型成员。这两个成员如何存储?
  • 对于引用类型,其实例的数据部分始终存放在堆里。既然两个成员都是对象数据的一部分,那么这两个成员都会被存放在堆里。
图片链接丢失
  • 如上图,尽管成员A是值类型,但它是MyType实例数据的一部分,因此和对象的数据一起被存放在堆里面。成员B是引用类型,它的数据部分会始终存放在堆里,还要注意它的引用部分也被存放在堆里。
  • 总结:对于引用类型的任何对象,它所有的数据成员(无论是值类型还是引用类型)都存在堆里。

9. C#类型的分类

图片链接丢失

10. 变量

  • 变量是一个名称,表示程序执行时存储在内存中的数据。
  • C#提供了4种变量
    • 局部变量 -> 在方法的作用域保存临时数据,表示类型的成员。
    • 字段 -> 保存和类型或类型实例相关的数据,是类型的成员。
    • 参数 -> 用于从一个方法到另一个方法传递数据的里你是变量,不是类型的成员。
    • 数组元素 -> (通常是)同类数据项构成的有序集合的一个成员,可以为局部变量,也可以为类型的成员。
10.1 变量声明
  • 变量必须先声明,再使用。
/// 变量声明,至少需要一个类型和一个名称。
int var01;

说明:变了声明完成了2件事,一件事是给变量命名为var01,并给它关联了一种类型int。另一件事是让编译器为变量分配一块内存。
10.2 变量初始化语句
  • 变量初始化语句有一个等号后面跟一个初始值组成。
// 变量初始化语句
int var02 = 10;

说明:声明变量时除了声明变量的名称和类型之外,还可以再声明变量时把它的内存初始化为一个明确的值。
  • 无初始化语句的局部变量有一个未定义的值,这个变量在赋值之前不能使用。试图使用一个未定义值的局部变量会导致编译器产生一条错误信息。
10.3 自动初始化
  • 一些类型的变量如果在声明是没有初始化语句,那么会被自动设为默认值,而另一些则不能。
图片链接丢失
  • 没有自动初始化为默认值的程序在为他赋值之前包含未定义值。哪些变量会自动初始化,哪些变量不能被初始化,后续章节会讲解。
10.4 多变量声明
// 声明一些变量,有些被初始化,有些未被初始化。
int var03 = 10; var4, var5 = 20;

说明:
1. 多变量声明中的变量必须类型相同。
2. 变量名必须用逗号分隔,可以在变量名后面包含初始化语句。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
int var06, double var07; // 错误写法,试图在一条语句中声明2个不同类型的变量。
10.5 使用变量的值
  • 变量名代表该变量保存的值,可以通过变量名来使用值。
string str01 = "Qinway";
string str02 = "C#图解教程";
Console.WriteLine($"我是{str1},正在看{str2}。");

控制台输出:
我是Qinway,正在看C#图解教程。

11. 静态类型和dynamic关键字

  • 每一个变量都包含变量类型,这样编译器就可以确定运行时需要的内存总量;以及编译器知道哪些部分应该存在栈上,哪些部分应该存在堆上。
  • 变量的类型在编译的时候就解析(确认),并且在运行时不能被修改,这叫做静态类型,C#是静态类型语言。但不是所有的编程语言类型都是静态的,例如Python就是动态类型的,它的变量在运行时才会解析。
    • 问题,如果我们想在C#中使用Python语言编写的程序集,但是Python语言的变量是在运行时解析的,那么C#语言在编译时是如何解析Python语言程序集里面的变量呢?
    • 答案是C#语言的设计者增加了dynamic关键字,这个关键字代表一个特定的C#类型,它知道如何在运行时解析自身。
  • 使用dynamic关键字,C#编译器不会对dynamic类型的变量做类型检查。
  • ※注意本小结表述的内容可能不准确※

12. 可空类型

  • 略。

结尾

书籍:C#图解教程

著:【美】丹尼尔 · 索利斯;卡尔 · 施罗坦博尔

译:窦衍森;姚琪琳

ISBN:978-7-115-51918-4

版次:第5版

发行:人民邮电出版社

※敬请购买正版书籍,侵删请联系85863947@qq.com※

※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

posted @ 2024-05-30 10:20  qinway  阅读(48)  评论(0)    收藏  举报