1. 程序的结构由哪些部分组成?
结构的组成包括:
(1)定义class:用于定义对象的属性和方法
(2)成员变量:定义在类、结构体或枚举中的变量
(3)成员函数(方法):定义在类或结构体的的代码
(4)命名空间(namespace):为防止文件名一致,导致系统无法区分,增加命名空间前缀来区分不同命名空间下的文件。
(5)结构体(struct):结构简单和对象非常相近
(6)Main方法:C#程序的入口
(7)注释:解释代码作用的文字
2. 什么是标识符、什么是关键字?
标识符:是用来命名变量、方法、类、结构体、命名空间等的名称。
•命名由字母、下划线和数字组成,开头必须以字母和下划线开始。
•标识符的大小写是敏感的
•不能使用C#关键字作为标识符
关键字:是C#语言预定义的、具有特殊含义的标识符。
比如:int(数据类型)、class(类定义)、if(控制流语句)、public(访问修饰符)等等
3. 什么是命名空间namespace?
命名空间是一种用于组织和封装相关类型的机制。以避免命名冲突和提高代码的可读性和可维护性。
4. 构造函数和析构函数的作用?
构造函数(Constructor):初始化新创建的对象,为对象分配资源,设置对象的初始状态。
析构函数(Destructor):释放对象在生命周期中使用的非托管资源,执行在对象对象被垃圾回收器(GC)回收之前的清理操作。
5. 数据类型有什么作用?分什么整数、小数、对象干嘛,多麻烦?
(1)内存管理:数据类型决定了存储在内存中的数据和种类的大小。
(2)性能:使用适当的数据类型可以提高性能。
(3)准确性:不同的数据类型有不同的精度和范围。
(4)代码可读性和便于维护:使用数据类型可以提高代码的可读性,有助于开发者理解代码意图,便于维护。
(5)运算和操作:数据类型决定了你可以对哪些数据进行运算和操作。
6. 值类型和引用类型的区别?
值类型:
(1)存储方式:值类型的值直接存储在栈内存中
(2)分配方法:值类型变量在声明时,系统会分配内存来存储该变量的值
(3)生命周期:值类型的生命周期与变量所在的作用域(Scope)相关。当变量离开其作用域时,其占用的内存会被自动释放。
(4)访问方式:通过变量名直接访问其值。
引用类型:
(1)存储方式:引用类型的值存储在堆(Heap)内存中,而变量本身则存储在栈上。引用变量存储的是对堆上对象的内存地址的引用。
(2)分配方法:引用类型变量在声明时,仅分配一个引用,真正的对象值在堆上分配。
(3)生命周期:引用类型的生命周期与垃圾回收(GC)相关。当没有任何引用指向堆上的对象时,垃圾回收器会释放该对象占用的内存。
(4)访问方式:通过引用变量访问堆上的对象。如果引用变量为null,则表示没有引用任何对象。
7. 栈和堆的区别?
分配方式:
栈:栈内存是由编译器自动分配和释放的
堆:堆内存则需要手动分配和释放。堆内存的分配通常通过new关键字来完成,用于创建对象的实例。
存储内容:
栈:通常保存着值类型数据,存储时有一定的顺序,遵循先进后出的原则。
堆:堆上存放的则多是引用类型,堆内存通常比栈内存更大,并且存储时没有固定顺序。
操作方式:
栈:访问栈内存中的数据比访问堆内存中的数据更快。
堆:堆内存中的数据则是通过引用来访问的,每次访问需要先查找引用所指向的位置,然后再进行操作。因此,堆内存的访问速度相对较慢。
生命周期:
栈:栈内存中的数据随着方法的结束而自动释放。
堆:堆内存中的数据则需要手动释放。
8. Struct结构体和Object对象的区别?
类型分类:
Struct:是值类型的一种,用于创建值类型的数据结构。
Object:通常是引用类型的实例
内存分配:
Struct:通常存储在栈(Stack)上,但也可以作为类的字段存储在堆(Heap)上。
Object:存储在堆上,变量包含的是指向堆上实际数据的内存地址。
构造函数:
Struct:虽然可以定义带参数的构造函数,结构体不允许定义析构函数。
Object:可以有多种类型的构造函数(无参、带参等),并且可以定义析构函数。
初始化:
Struct:结构体内的字段必须在所有情况下都被初始化。如果不使用new操作符,只有在所有的字段都被初始化之后,结构体变量才能被使用。
Object:类的字段可以在声明时初始化,也可以在构造函数中初始化,或者在类的其他成员方法中初始化。
赋值和传递:
Struct:结构体变量赋值或传递给方法时,传递的是其值的副本,对副本的修改不会影响到原始变量。
Object:对象变量赋值或传递给方法时,传递的是引用的副本(即内存地址的副本),对对象的修改会影响到原始对象。
继承和多态:
Struct:不支持继承,即不能从其他结构体或类继承,也不能被其他结构体或类继承。
Object:类支持继承,可以继承自其他类,也可以被其他类继承。
用途:
Struct:通常用于表示一个小的数据组合,这些数据组合在逻辑上属于一个单元。结构体主要用于封装一些方法或属性,以便于调用,减少代码运算量。
Object:类是创建复杂数据结构和行为的基础,可以包含字段、属性、方法、事件等。
9. 什么是隐式类型转换,什么是显式类型转换?
隐式类型转换:隐式转换是编译器自动执行的,不需要程序员明确指定的类型转换。当一种类型的数据可以安全地转换为另一种类型时,编译器会自动进行隐式转换。
显式类型转换:定义:显式转换是在编译时,需要使用强制类型转换操作符来手动进行的类型转换。
10. 可空类型是什么意思?有什么作用?
在C#中,可空类型是一种特殊的数据类型,它允许值类型的变量存储null值。在C#中,值类型默认是不能为null的,但在一些情况下,需要表示一个值类型的变量没有有效的值,可以使用可空类型。
可空类型的主要作用和特点包括:
表示缺失值:某些值可能是可选的,或者由于某种原因而缺失。使用可空类型可以明确表示这种情况,避免使用特殊值(-1、0)来表示缺失,从而提高代码的可读性和可维护性。
与数据库交互:当从数据库中读取数据时,经常会遇到字段值为null的情况。使用可空类型可以安全地处理这些null值,避免在将数据库中的null值转换为C#中的值类型时引发空指针异常。
区分空值和默认值:对于值类型,它们通常有一个默认值。使用可空类型可以明确表示一个变量是否有赋值,而不与值类型的默认值混淆。
在声明可空类型时,需要在值类型后面添加一个问号(?)。例如,int?表示一个可以为null的整数类型。
??:这是C#中的空合并运算符。这个运算符用于提供一个默认值,如果左侧的表达式为null,则返回右侧的表达式。例如:
int? a=900;
int b=a??100