本系列为dotnettutorial教程中关于C#语言的一些基础知识,前面语言基础介绍部分就简单过一下没做记录了。主要记录一些平时可能关注比较少,或是非常重要的一些知识点。
参考连接: C#.NET Tutorials
基础知识
重写对象Equals,ToString方法:默认ToString返回对象的命名空间+名字,Equals默认与==操作相同,当比较对象时,两个比较两个对象引用的内容是否一致。
check/uncheck关键字:check关键字用于检查操作符左侧的变量是否会溢出,如果溢出抛出运行时错误。uncheck和编译器默认动作一致,不做检查。
OOP面向对象
- 构造函数
析构函数
- 析构函数只能在类中定义,不可用于struct中。
- 只能定义一个析构函数,不可以有重载,不可以有参数,不可以有访问修饰符。
- 析构函数无法显示调用,它是由GC来触发。可以请求GC执行析构GC.Collect()
- 应用程序中应该避免使用空的析构函数。类包含析构函数的话,会创建一个Finalize函数链入口。如果析构函数仅调用父类析构函数,析构函数未执行任何操作,将会对垃圾回收性能造成影响。
垃圾回收
托管对象:运行在dotnet framework的CLR(公共语言运行时)中,由C#、VB.NET、F#等语言编写的程序。
非托管对象:需要自己的运行环境,如C、C++、Java等开发的程序。
垃圾回收是一个独立服务,定期执行回收不再使用的托管对象(仅回收托管对象,非托管对象不受垃圾回收控制)。
机制:用一个虚拟的代的概念,来作为回收内存依据。三代:0代、1代、2代。
代用来表示对象是否需要继续被使用。初创建的对象,归入0代,垃圾回收开始运行,检查0代中是否有对象不再需要,如有重置其内存;其余需要继续使用的归入1代。垃圾回收再次运行时,同样执行0代检测,再执行对1代对象的检测。如1代中有不再使用的对象,释放其内存;并将1代中继续使用的对象归入2代中。
优化:归入1代和2代中的对象,表明他们需要更多的被使用,在应用程序中需要驻留的时间更长。因此,垃圾回收不需要像检测0代一样,每次运行都去检测1代和2代的对象。这样就能够达到提升效率的目的。0代中越多对象,越高效,越多的内存能被利用到。
托管对象,可以不需要析构函数,默认创建对象存放在0代中,这样内存利用效率最高,垃圾回收会尽快回收不再需要使用的对象。
非托管对象,需要手动释放。建议在调用非托管对象的类中,实现IDispose接口,使用公共的Dispose方法。
1 | public class MyClass2 : IDisposable |
- disposedValue: 该变量用来标记是否为重复调用。
- Dispose(bool disposing): 在该方法内编写实际销毁托管资源和非托管资源的代码程序。disposing作为输入变量,指示是否需要销毁托管资源。第一次请求时,该变量检查disposedValue值为false,执行clean-up活动,并在结束时将值设置为true。重复调用时,则不再执行clean-up活动。
- ~UmmanagedResource(): 默认该析构函数代码都被注释掉了。如果取消注释,则需要自己编写清理托管资源的程序,然后调用Dispose(false)方法来清理非托管资源。只有当Dispose(bool disposing)方法包含了释放非托管资源的程序时,才能重写析构函数或终结器函数。
- Dispose(): 该方法用于暴露给外部程序,用于外部程序调用来清理托管和非托管资源。在该方法内部调用私有方法Dispose(true)来真正实现清理工作。如果重写析构函数或者终结器函数,还需要调用GC.SuppressFinalize(this),告诉CLR不要调用析构函数或终结器函数。只有重写了析构函数或终结器函数才需要将该行代码取消注释。
总结
托管资源不需要考虑垃圾回收,交给GC即可。(比如下面封装中创建的Bank类)
包含非托管资源的类,需要实现IDispose接口(比如FileStream类,它的父类Stream就实现了IDispose接口)
StreamIDispose.png
- 访问修饰符
类的访问修饰符只能是public 和 internal
修饰符 | 类内部 | 继承类 | 非继承类 | 不同程序集继承类 | 不同程序集非继承类 |
---|---|---|---|---|---|
private | YES | NO | NO | NO | NO |
public | YES | YES | YES | YES | YES |
protected | YES | YES | NO | YES | NO |
internal | YES | YES | YES | NO | NO |
protected internal | YES | YES | YES | YES | NO |
private protected | YES | YES | NO | NO | NO |
- 封装
优点: 数据保护(保存数据前进行验证)、 实现数据隐藏、 安全、 灵活性、 控制
使用属性get、set提供数据存取,类似于使用两个公共的方法
1 | public class Bank |
- 抽象: 把必要的功能展示出来并不关注具体实现细节的过程。
- 本文作者: 达文西
- 本文链接: https://edsiongithub.github.io/2022/11/16/38/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!