作为c#程序员,这些知识点你是否都了解?

本文涵盖C#编程中的各种技巧,包括字符串操作、类型转换、泛型使用、线程同步等多个方面,帮助开发者提高代码质量和性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、字符串操作
(1)避免装箱
string str1 =”str1”+9;(发生装箱)
string str2 = “str2”+9.ToString();(不装箱)
(2)避免分配额外的内存空间。
string s1 = “abc”;
s2 = “123” + s1 + “456”;
创建3个字符串对象,执行一次string.Contact()方法。
注意:
string s2 = “123”+”abc”+”456”;//等价于string s2 = “123abc456”;
在编译时直接拼接成一个字符串
尽量使用StringBuilder类和string.Format()方法完成字符串拼接。
string a = “t”;
string b = “e”;
string c = “s”;
string d = “t”;
string. Format(“{0}{1}{2}{3}”,a,b,c,d);

2、类型转换
(1)使用类型转换运算符
隐式转换和显示转换(强制转换)
基元类型都具有转换运算符,自定义类型通过重载转换运算符实现类型转换。
(2)使用类型内置的Parse/TryParse,ToString()/ToDouble()/ToDateTime()方法。
(3)使用帮助类System.Convert类、System.BitConverter类来进行类型转换。
System.Convert提供将基元类型转换为其他基元类型的方法。
自定义类型实现IConvertible接口,System.Convert可以将类转换成基元类型。
System.BitConverter提供了基元类型与字节数组之间的相互转换的方法。
(4)使用CLR支持的转型
具有继承关系的类之间的转换:子类转换成父类使用隐式转换;父类转换成子类使用显示转换,也可使用as操作符,从效率角度考虑,建议使用as操作符,转型前还可以使用is来判断类型是否兼容。
不具有继承关系的类之间相互转换可以重载转换运算符来实现。

3、实现比较器
对象实现IComparable接口后,包含该对象的集合便可以调用Sort()方法对集合进行排序,排序依据是对象的CompareTo()方法的逻辑。还可以通过实现IComparer接口定义比较器,在排序时将比较器提供给Sort()方法,便可以依据比较器提供的逻辑来进行排序。

4、重写Equals()方法需要注意的地方
重写Equals()方法的同时,需要重写etHashCode()方法,基于键值的集合中根据Key来查找Value时,CLR内部使用的是对象的HashCode,HashCode由GetHashCode()方法返回。GetHashCode()方法应该基于那些只读的属性或特性生成HashCode。
重写Equals()方法的同时,应该实现一个类型安全的接口IEquatable。

5、为类型输出格式化字符串
实现IFormattable接口为类型提供格式化字符串输出。(主动型)
实现IFormatProvider与ICustomFormatter接口定义格式化器。

6、使用foreach遍历集合的过程中,不能进行增加删除操作;
使用for遍历集合的过程中,可以进行增加删除操作。
foreach通过检测迭代器内部维护的版本号来判断是否可以进行增删操作。

7、.NET中的集合类(包含泛型类)
(1)Stack、Queue
(2)Array
(3)ArrayList
(4)List
(5)Dictionary
(6)LinkedList
(7)SortedList/SortedDictionary/SortedSet
(8)ConcurrentBag/ConcurrentDictionary/ConcurrentQueue/ConcurrentStack(线程安全)

8、泛型优点
(1)性能
避免装箱拆箱
(2)代码重用
提供代码模板的功能
(3)类型安全
编译期的类型检查

9、协变和逆变
在泛型类型参数前使用out和in关键字表示该类型参数是协变或者逆变的。
现有类a是类b的子类,那么a变成b就是协变,b变成a就是逆变。
out和in关键字可以使用在泛型接口和委托中修饰泛型类型参数。
被out修饰的泛型类型参数,只能作为返回值,很显然,能够返回b的接口肯定也能返回a,这就是协变。a–>b 协变
被in修饰的泛型类型参数,只能作为输入值,很显然,输入值需要被修改,能改修改a的地方肯定能修改b。b–>a 逆变

10、抽象方法和虚方法
抽象方法是只有定义、没有实际方法体的函数,它只能在抽象类中出现,并且在子类中必须重写;虚方法则有自己的函数体,已经提供了函数实现,但是允许在子类中重写或覆盖。只有类的成员函数才能为虚函数,静态成员函数不能是虚函数、内联函数不能是虚函数、构造函数不能是虚函数,析构函数可以是虚函数。

11、关于资源管理
如果类型使用到非托管资源,或者需要显式地释放托管资源,就应该让类型实现IDispose接口。
即使提供了显式释放资源的方法,也应该在终结器中提供隐式清理,以避免调用者忘记调用该方法而带来的资源泄漏。
在显式释放资源的方法Dispose中应该调用GC.SuppressFinalize(this)来告知垃圾回收器资源已被显式地释放,隐式释放资源就没有必要了。
实现IDispose接口的类必须提供一个受保护的虚方法Dispose,以此来提醒子类在实现自己的清理方法时注意到父类的清理工作,调用base.Dispose()方法。
在Dispose方法中释放托管和非托管资源,而在终结其中只需要释放非托管资源,托管资源交给垃圾回收器处理。
要了解常见的非托管资源,比如数据库连接、文件操作、Windows内核对象、套接字、COM对象等。
使用GC.Collect()方法可及时释放所有资源。

12、关于序列化和反序列化
使用Serializable特性将类标记为可序列化。
使用NonSerialized特性将无用字段标记为不可序列化,NonSerialized特性不可用于属性上,因为属性本质是方法。
使用改进特性field:NonSerialized将事件标记为不可序列化。
使用OnDeserialized、OnDeserializing、OnSerialized、OnSerializing特性更加灵活的处理序列化和反序列化过程。
实现ISerializable接口使类型支持序列化和反序列化操作。
当类实现ISerializable接口的同时,使用了Serializable特性。格式化器在序列化一个对象时,将忽略Serializable特性,转而调用接口的相应方法来完成序列化和反序列化操作。

13、关于异常
享受异常带来便利的同时,也不要忘记“效率”问题,TryDo模式是应对此类问题的一个很好的实践。
用抛出异常代替返回错误码,因为错误码需要随着程序暴露新问题时不断更新,不可能一开始就定义好所有的错误码。
对于何时引发异常,可以这样考虑:正常的业务流程不应使用异常来处理;不应该总是尝试去捕获异常或引发异常,而应该允许异常沿调用堆栈往上传播;若运行代码后会造成内存泄漏、资源不可用或者程序状态不可恢复时,则引发异常;在捕获到异常信息时,需要包装一些更有用的信息时,则引发异常;如果捕获的底层异常在高层上下文中没有什么意义,则可以重新引发更有意义的异常。
捕获异常重新引发异常时,使用Inner Exception保存内部异常。
finally内的代码会在方法return之前执行,哪怕return是在try块中。
尽量不要嵌套异常,确实需要捕获中间异常进行处理再抛出异常,请使用throw,而不要使用throw err,这会重置堆栈信息。
尽量不要“吃”掉异常。
尽量不要在循环中处理异常。
总是处理未捕获的异常(UI线程,非UI线程)。
主线程无法捕获子线程抛出的异常,所以子线程的异常应该在子线程内部处理,也可以用事件回调的方式将子线程的异常包装到主线程,也可以在捕获到子线程异常后切换到主线程重新引发异常。
应在finally中释放资源,避免资源泄漏。

14、线程同步
(1)锁
lock和Monitor
(2)EventWaitHandle(子类为AutoResetEvent、ManualResetEvent,父类为WaitHandle)
内部维护一个由内核产生的布尔类型对象。
(3)Semaphore(父类为WaitHandle)
内部维护一个由内核产生的整型对象。
(4)Mutex(父类为WaitHandle)
跨应用程序域的同步。

15、线程锁对象需要满足的条件
锁对象在多个线程中必须是可见的同一个对象。
值类型和字符串类型对象不要用作锁对象。

16、前台线程和后台线程
前台线程不结束,进程不会退出;进程退出时,所有后台线程会一起结束。
线程默认为前台线程,线程池中的线程默认为后台线程。
除非线程正在执行事务或占有的某些非托管资源需要释放时,才使用前台线程,不然都尽量使用后台线程。

17、线程优先级
Windows是基于优先级的抢占式调度系统,优先级高的处于就绪状态的线程总是先被执行。
线程优先级分为Highest,Normal,BelowNormal和Lowest。
使用Thread和ThreadPool新起的线程,默认优先级都是Normal。
尽量不要去修改线程的优先级,对于那些运行时间短、能即刻进入等待状态的线程可以适当提高线程优先级。

18、线程停止和取消
线程不能立马执行,同样,线程也不能立马停止。
线程需要完成手头的工作(如执行非托管代码)后才能停止。
FCL提供协作式取消机制来取消线程,协作式取消机制关键类为CancellationTokenSource。

19、线程数量
分析此问题时,需要考虑线程切换的开销,线程占用的内存。
建议可以更多考虑ThreadPool和BackgroundWorker来取代Thread。

20、使用Task代替ThreadPool
ThreadPool存在不足包括:不支持线程的取消、完成、失败通知等交互性操作;不支持线程执行的先后次序。Thread正好可以弥补这些不足。有些场景甚至可以使用Parallel来取代Task的操作。

21、安全相关
使用checked关键字在发生溢出时抛出异常。
MD5被广泛应用于密码验证和消息体完整性验证。
多次使用MD5算法可以起到改进MD5的作用。
通过HASH来验证文件是否被篡改,MD5算法是最通用的HASH算法。
加密算法分为对称和非对称,对称算法效率高,开销小,适合进行大数据量的加解密。非对称加密的优点是用于解密的密码永远也不需要给对方,缺点是运算量大,算法复杂,适合数据量小的场合。
使用SSL确保通信中的数据安全,SSL利用数字证书技术(非对阵加密),保证数据的唯一性、不可篡改性、不可抵赖性。

22、定义类时你能想到些什么?
实现基类的ToString()方法、(Equals()+GetHashCode())方法
实现IEquatable接口(重写Equals()方法时需要)
实现IConvertible接口
实现IDispose接口
实现TryDo模式
重载操作符(赋值、转换、==)
实现比较接口IComparable(实现比较器接口IComparer)
实现IFormatProvider与ICustomFormatter接口定义格式化器。
实现ICloneable接口提供深浅拷贝。
实现接口时,需要考虑对应泛型接口的实现。
自定义集合类型,需要考虑实现IEnumerable接口。(同时实现IEnumerator接口定义迭代器)
自定义集合类型,可考虑是否实现ICollection接口。
定义泛型接口或者委托时,需要考虑协变和逆变。
对需要显式释放资源的类需要实现IDispose接口。
实现ISerializable接口使类型支持序列化和反序列化操作,也可以使用Serializable特性。

C#程序员书籍推荐 1、C#编程 C# Windows Form 程序设计------对熟练掌握WinForm编程基础比较有用,看得时候建议将书中的例子从头到尾做一遍,这样会有比较好的收获,否则,学习效果一般。 C# XML从入门到精通 ------这本书前半部分讲的关于XML的基础操作比较有用,后半部分如果对XML有兴趣的话也可以仔细看看,毕竟XML是现在的一个主流方向。 C#高级编程 ------大家公认的一本C#经典教课书,但是太厚了,要有耐心仔细看下去,不然效果就不是很好。 说明:个人认为看编程的书就要敲代码,如果将书中的例子做一遍,只看书,效果会大大折扣的,尤其对于刚开始学习编程的人。 2、代码质量 重构-改善既有代码的结构 ------一本与设计模式齐名的经典著作,对你的代码规范、代码质量以及软件设计都有很大的帮助。 个体软件过程 ------一本偏重于软件工程的书,也许你会觉得很无聊,但是如果坚持下来,你会觉得效果真的就如书上所说。我只坚持了一个月,但是感觉收获已经很大。 说明:软件代码质量和个人的编码习惯、编码风格有很大关系,当水平达到一定之后,你的编码习惯、编码风格如果有问题的话,会阻碍你的进一步提高的。编码风格、编码习惯的改进中再坚持。 3、设计思想 UML与模式应用 ------我看到的第一本让我佩服的书,也是OO方面我的启蒙书,这本书我看了三遍,笔记记了一大堆,每次都有新的收获,而且最近还计划在仔细阅读一遍! 设计模式 可复用的软件设计基础------一本计算机界公认的经典著作,这本书对于入门者可能有点困难,但是这本书看十遍都不多!绝对的经典!如果以后想做软件开发的话,个人建议将这本书看五遍以上! 面向对象编程导论(原书第3版)------一本对OO讲述比较全面、比较经典的书籍。 说明:设计思想方面,OO是现在的主流,东西很灵活,要多看相关的书籍,多在实践中运用。同时,看着部分的书,一定静下心来人真看。 4、软件工程 应用极限编程-积极求胜 ------极限编程现在很火,也是你无法全部接受它,或者你周围的环境不能实施它,但是其中的一些思想、最佳实践可以用在你的工作中,无论是编码还是设计,对你的思路都回有很大好处的! RUP导论 ------RUP和XP是现在很火的东西了,这本书对RUP进行了很好的描述,书很薄,但是能够让你很好的全面地认识RUP。 用例 通过背景环境获得需求------用例分析是RUP中很重要的一个环节,这本书讲的很好,无论在需求分析、软件设计方面都会对你有很大启发。 说明:软件工程现在门类很多,可能很多东西我们周围没有使用的环境,或许我们不会从事软件过程管理,但是其中的很多思想对我们个人的软件开发都会有很大的帮助! 5、软件测试 软件测试的艺术 ------可以帮你纠正很多对软件测试的误区! 单元测试之道 C#版-使用NUnit-----NUnit可是被誉为.net程序员必备的一项工具啊!很不错的一本书,值得仔细看看! 测试驱动开发 ------经典的书籍,虽然是XP中核心的内容之一,但是即使单独运用它,也会给你意外的惊喜。 说明:软件测试并不只是手工点点按钮,其实内容很多的。好的测试员,不仅需要对测试领域有深刻的理解,也需要很高的编程功底。即使你不想从事测试工作,学习这些东西,也会对你的编程水平、代码质量有很大的帮助。 个人认为,看一本书,尤其是经典的著作,看十遍都不为过。同时,看书的过程还要学会发现在其感兴趣的、不了解的内容,然后自己再找相关的书籍看。以上的书只是我看过的、个人认为比较经典的书籍,可能个人情况不一样,兴趣点不一样,对我来说经典的书籍不一定对大家经典,但是,要学会自己查资料、学东西的能力,这才是最重要的。如果你能有毅力用一年或者一年半的时间把上面的书籍吃透,再加上公司项目的锻炼,那恭喜你,你的编程和设计能力在你们同学之中肯定可以稳居前10%。 读书,尤其是软件方面的书,其实是很累的,可能读一本书不累,但是如果你能每天坚持三个小时认认真真地看书,能够将一本经典之作认认真真读五遍,而且一直认认真真,那你的毅力真地令人佩服,同时,你的汗水带给你的会是很多的惊喜! 首先让自己喜欢读书,然后学会读书,再学会自己找书读,自己查资料、解决问题……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值