C#基础
简述 值类型 和 引用类型 的区别:
1)值累心光存储虎仔内存栈中,引用类型数据存储在内存堆中。而内存单元中存储的是堆中存放的地址。
2)值类型存取快,引用类型存取慢
3)值类型表示实际存储的数据,引用类型表示指向存储在内存堆中的数据的指针和引用
4)栈的内存是自动释放,堆内存中是.Net中会由GC来自动释放
5)值类型继承自 System.ValueType ,引用类型继承自 System.Object
描述 Interface 和 抽象类 之间的不同
语法不同:
1.抽象类中可以有字段,接口没有
2.抽象类中可以有实现成员,接口只能包含抽象成员
3.抽象类中所有成员修饰符都是可以使用,接口中所有的成员都是对外的,所以不需要修饰符修饰。
用法不容:
1.抽象类是概念的抽象,接口关注行为
2.抽象类的子类和父类的关系是泛化关系,实现类和接口之间关系是实现关系
3.一个类只能继承一个类,但是可以实现多个接口
c#中 List,Hashtable,Dictionary 区别?
List是对数组的封装,当List<T>对象的Item元素数量超过了Capacity,List<T>对象重新生成一块
大小是原来Capacity的两倍内存空间,然后将当前所有Item元素以及待添加的元素复制到新的内存空间。
频繁的添加数据消耗大,但数据查询速度快,内存连续。
Hashtable、Dictionary它们的内存是用key值根据hash算法算出来的,它们的内存区域是不连续的,
所以在遍历的时候难免会对内存进行换页操作这样遍历的时间就长;
Dictionary :
1、类型安全,对值类型没有装箱拆箱操作;
2、在单条数据的读取上速度快;
3、数据的存放是有序的
Hashtable :线程安全,适合多线程,无序;
简述 StringBuilder 和 String 的区别?
string是字符串常量
stringBuffer是字符串常量,线程安全
stringBuilder是字符串变量,线程不安全
string类型是不可变的对象,当每次对string进行改变时都需要生成一个新的string对象,
然后将指针指向一个新的对象,如果在一个循环里面,不断改变一个对象,就要不断的生成新的对象,
所以效率很低。建议不断更改string对象的地方不要使用string类型。
stringBuilder对象是对象在做字符串连接操作时在原来的字符串上进行修改,改善了性能。连接操作
频繁是,使用stringBuilder对象。
索引器与属性的区别 :
1)索引器以函数签名方式this来标识,而属性采用名称来标识,名称可以任意
2.)索引器可以重载,而属性不能重载
3)索引器不能以static来声明,而属性可以
c#解释代码编译:
1.通过c#编译器将源代码编译为托管代码
2.将创建的代码组合到程序集合
3.加载公共语言运行时CLR
4.通过CLR执行程序集
类型安全之拆箱和装箱:
引用类型之间的类型转换
将一个对象转化为任何基类类型
转换时,将等号左边的和等号右边的类型进行转换。
如果左边是基类,则安全,
否则编译异常,必须显示转换
Object a = new Manager() 正确, Object是基类
装箱的过程:
int x = 1023;
object o = x; //装箱
执行第一句,托管堆没有任何东西。栈上有一个整型变量。第二局就是装箱,因为Object是引用类型,必须指向堆上的某个对象,而x是值类型,没有堆上的对应对象。
所以需要使用装箱,在堆上创建x.
装箱的步骤:
1.分配内存。 这个例子需要一个整型变量,加上托管堆上所有对象都有的两个
额外成员【类型对象指针和同步块索引】。类型对象指针指向int类型对象。
2.值类型的变量赋值到新分匹配的堆内存
3.返回对象的地址
拆箱的过程:
拆箱不需要额外的内存。
int i = 1;
object o = i;
var j = (byte)o;
拆箱步骤:
1.如果已经装箱实例为Null,抛出NullReference异常
2.对象不是null但是类型不是原先未装箱的值类型,则抛出InvalidCast异常
3.获取已经装箱实例当中值类型字段的地址
4.创建新的值类型变量,其值使用第三步获取到的值
类(class) 和 结构(struct) 的区别?
结构对象可能分配在堆上吗?何时考虑使用结构体?
类和结构是c#两个最主要的研究对象。
1.结构是值类型,继承自 System.ValueType,而类是引用类型
2.值类型不能继承,所以结构struct不能继承
3.结构struct作为值类型,但是结构中可以存在引用类型
【但是如果struct中包含引用类型,建议使用类】
结构体如果包含引用类型,则部分分配在堆上
结构:
结构作为值类型,
结构是值类型,new运算符和其他引用类型的工作方式不同。
new运算符并不分配堆中内存,只是调用相应的构造函数。
结构中可以存在构造函数,但是结构内部不能存在无参构造函数。
Csharp 属性访问器
类成员包括变量和方法,希望其他类访问成员变量,则定义为共有public,那么这个成员变量就可随意访问,但是不利于数据安全性。
c#通过属性特性读取和写入字段【成员变量】,而非直接读取和写入,借此提供对类中字段的保护,属性作为c#面相对象技术中封装性的体现。
属性和字段的区别:
- 属性作为逻辑字段,是字段的扩展,不占用实际的内存
- 属性可以被其他类访问,而 非public字段 不能直接访问
- 属性可以对接受的数据在范围上做限定,但是字段不能
使用属性的情况:
- 要求字段只读或只写
- 需要限制字段取值范围
- 在改变一个字段的值时希望改变对象的其他状态
使用字段的情况:
- 允许自由读写
- 取值范围只受到数据类型约束而无其他任何限制
- 值变动不引发类中其他成员的变化
设计字段是为了便于内部方法使用,而尽量与外界隔绝;设计属性考虑的是方便外界的使用,但是不让外界知道的数据一律不给。
SerializeField 的用法
如果a是公有的序列化变量。
public int a;
[HideInInspector]
public int a;
这样a可以在程序中被代码赋值,但不会在面板中看到,也不能手动设置赋值。
- 如果a是私有的序列化变量,你想在面板中读取并赋值,那么用:
[SerializeField]
private int a;
- 如果a是私有的序列化变量,你想在面板中读取,但是不赋值,那么用:
[HideInInspector][SerializedField]
private int a;
public int b
{
get{return a;}
}
- 如果a是私有序列化变量,你不想在面板中做任何操作(不想看到,也不想写),但是想要在程序中给它赋值,那么用。
[HideInInspector][SerializedField]
private int a;
public int b
{
get{return a;}
set{a = value;}
}