开发者论坛

 找回密码
 注册 (请使用非IE浏览器)
查看: 4592|回复: 0

[讨论] C#基础知识简单梳理

[复制链接]

0

精华

-4

贡献

48

赞扬

帖子
39
软币
293
在线时间
22 小时
注册时间
2015-8-24
发表于 2016-8-10 17:10:01 | 显示全部楼层 |阅读模式
本文是一个菜鸟所写,本文面向的人群就是像我这样的小菜鸟,工作一年也辛辛苦苦学习了一年,一直没有机会梳理一下自己的知识,最近花了一些时间整理了一些C#基础知识,也算是对过去的一年做个回顾把~
文章有点长,请自带瓜子和茶吧,请看下面C#基础知识简单架构图,不可能100%的全面,请见谅啊...
1.值类型和引用类型
  1.1堆和栈
  简单的说值类型存放在堆栈上面,引用类型的数据存放在托管堆上面(它的引用地址却存放在堆栈上面)!
  栈:它是一个内存数组,是一个先进后出的数据结构!
  栈的特征:数据只能从栈顶进,从栈顶出!
  堆:它是一个内存区域,可以分配大块区域存储某类型的数据,与栈不同的是它里面的数据可以任意排序和移除!
  下面是园子的一张图,贴上来供大家参考啊!
问     题值  类  型引 用 类 型
这个类型分配在哪里?分配在栈上分配在托管堆上
变量是怎么表示的?值类型变量是局部复制引用类型变量指向被分配得实例所占的内存
基类型是什么?必须继承自System.ValueType可以继承自除了System.ValueType以外的任何类型,只要那个类型不是sealed的
这个类型能作为其他类型的基类吗?不能。值类型是密封的,不能被继承是的。如果这个类型不是密封的,它可以作为其他类型的基类
默认的参数传递是什么?变量是按值传递的(也就是,一个变量的副本被传入被调用的函数)变量是按引用传递(例如,变量的地址传入被调用的函数)
这个类型能重写System.Object.Finalize()吗?不能。值类型不好放在堆上,因此不需要被终结。可以间接地重写
我可以为这个类型定义构造函数吗?是的,但是默认的构造函数被保留(也就是自定义构造函数必须全部带有参数)当然!
这个类型的变量什么时候消亡?当它们越出定义的作用域时。当托管堆被垃圾回收时。
  1.2装箱和拆箱
    
  这类的文章真的多了,再总结就没多大的意义了,看的时候多写写代码,多想想,就会明白的!
2.接口,抽象类,封装,继承,多态
  接口和抽象类这两个概念还真不容易理解,有的时候理解一半,换一种方法考考你,你就会晕,到现在说实话我还没完全懂,一直没有把握它们的精髓,最近在看<<你必须知道的.NET>>,这是第二次看,收获很多...
大家还是有时间多看看<<你必须知道的.NET>>,这本书可以说是很详细的讲解了OO思想,还有看看设计模式的书,多想多练,可以时间会长一点,不过总有一点我们会开窍的...
  这种东西不是通过总结一下就能熟练运用的,不过你起码要有一点面向对象的思想,要想有这种思想必须学习前辈留下的知识总结,这种才能理论结合实践,才能深入的了解OO思想
  推荐文章:细细品味C#——抽象、接口、委托、反射(感谢虾皮老师啊...)
3.迭代器
  主要是对foreach的深入理解,以及对两个接口的深入剖析(包括它们的泛型结构):IEnumerable(可枚举类型),IEnumertor(可枚举数),文章入口:使用IEnumerable和IEnumerator接口从yield关键字看IEnumerable和Collection的区别
4.泛型
  泛型保证了类型安全,避免了装箱和拆箱的操作,提高了性能,可复用性也得到了很大的提高,下面就来说说基本的泛型语法吧!
  项目中对于泛型和委托的结合运用也很多见,很多人不是为了语法而学习,而是泛型的扩展性让我们必须要知道它,把它实实在在的运用到项目中去,提高扩展性...
  泛型语法不是很复杂,包括定义泛型类型,泛型方法,指定泛型约束,还有泛型约束包括只包括哪些类型等等,这些语法只要花些时间就能明白了,难的是一种思想,o(︶︿︶)o 我还很菜啊...
  推荐文章:细细品味C#——泛型系列专题(虾皮帮我们已经整理关于泛型的精彩文章,看完之后会有很多的收获)
5.集合
  5.1一般集合
    .NET Frameword中关于集合的类存储在System.Collections命名空间下,其实一开始学习的时候感觉集合这个东西很神秘,能动态增加,删除,选择数据(比数据好用多了),可是在学习之后,它的神秘感也随之消息,因为集合的底层代码跟数组有着密切联系的,请看:学习之路二:关于集合和数组内在联系的深入了解(里面也有个链接,可以点击学习)!
    下面是非泛型集合类之间的关系图:
    
  5.2泛型集合
自从.NET Framework引用泛型概念之后,它在C#编程方面掀起了一个泛型热潮,泛型实在太好用了,不仅是类型安全,可扩展性,重要的是在性能方面有了显著提高,这让我们苦逼的程序猿看到了曙光,哈哈...
    泛型集合类存储在System.Collections.Generic以及System.Collections.ObjectModel命名空间下,下面是集合类之间的关系图:
    
  推荐文章:细细品味C#——泛型系列专题(有个pdf文件,下载下来回家慢慢看,同志们)
6.反射
  反射这东西两面性很极端,很多人说它的坏,也有很它在某些方面有着重大的作用,下图是关于类型反射所需要用到的类之间的关系图:
  除了类型反射之外,还有一种是程序集的反射,功能比较强大,可是我对它的研究比较少,我就推荐几篇好文章把(下面几篇文章我也正在学习中)...
  推荐文章 :  1..Net 中的反射(序章) - Part.1
            2..Net 中的反射(查看基本类型信息) - Part.2
            3..Net 中的反射(反射特性) - Part.3
            4..Net中的反射(动态创建类型实例) - Part.4
7.特性(Attribute)
  特性这个东西,在面向对象编程中有着非常重要的最用,在架构设计框架的时候,考虑使用特性的几率会非常的大!
  特性结合反射技术就可以实现依赖注入,以前看到公司一个项目在写测试代码的时候,总是给每个方法加上[RollBack]的特性,当方法结束后,所有数据库的操作都将会回滚,我很费解,因为RollBack是自己定义的,怎么就一加上这个特性就自动完成回滚了!
  下面就是完整的Rollback代码,可是我在使用它的时候遇到一个问题 ,就是它只可以用于单元测试,我尝试着把它用于一般的方法当中,可是一直没有实现回滚功能,我感到很费解,有兴趣的朋友可以帮我看看...
View Code
    只能在单元测试里面进行调用:
[url=][/url]

1   [TestClass()] 2     public class ProgramTest : TestFixture  //继承这个类 3     {48         [TestMethod()]49         [RollBack()]  //添加这个RollBack特性,就能实现回滚了50         public void MyTestTest()51         {52             SqlConnectionStringBuilder connectionString = new SqlConnectionStringBuilder53             {54                 DataSource = @"LBDZ-20120514VC\SQLEXPRESS",55                 InitialCatalog = "My",56             };57             connectionString.IntegratedSecurity = true;58 59             using (SqlConnection conn = new SqlConnection(connectionString.ToString()))60             {61                 conn.Open();62                 SqlCommand cmd = conn.CreateCommand();63                 cmd.CommandText = "INSERT INTO dbo.MyTable (    id) VALUES ( 6666 )";64                 cmd.ExecuteNonQuery();65                 Console.WriteLine("OK");66             } 68             Assert.IsTrue(true);69         }70     }
[url=][/url]

  Question:这个RollBack我至今还没有弄懂它怎么来实现的,如果那个园友能看懂的话,可以私信给我或留言给我,我会打心里感谢你的,可能会涉及到AOP和IOC的知识,希望大家帮帮我把,纠结了很长时间啦...
    推荐文章: 1. 关于C# 中的Attribute 特性
          3. Attribute在.net编程中的应用(一)          
8.委托和事件
  其实把理解事件跟字段和属性联系起来,虽然这样说可能会不严谨点,但是从一些大的方面讲事件就是对委托的封装,类似于属性对字段的封装,这种说法还是行得通的!
  想要定义一个完整的委托和事件,需要经历一下步骤(需要注意一些命名规范):
① 定义事件 → 委托使用微软提供的EventHadler<TEventArgs>泛型委托,一般都会有两个参数:
A)   “object sender”定义的事件依附的对象,也就是事件定义在那个类中,那么这个参数就为这个类的实例化对象,一般都会用“This”!
B)   “EventArgs e”也就是用于传递一些参数信息的对象,也可以使用自己定制的参数了
② 创建参数类 → 如果有必要定制的数据参数类(这个类似于创建自己的实体类用来传递信息),这个参数类应该继承于EventArgs这个类!
③ 执行事件 → 其实在执行事件的时候还是有一定的规范的,比如方法名必须为“On+事件名”,还有在执行事件要判断下时候为null,,然后在调用!
④ 注册事件 → 调用事件(在传递事件对象的时候最好用“this”关键字)
⑤ 依附事件的方法 → 最后定义依附在这个事件中的方法,也就是执行这个事件的方法体,深入了解,其实依附事件中的方法其实都最终依附在事件衣服的委托中,这个委托会生成一个委托实例,以及一个委托链!
委托和事件定义语法:
委托: 访问修饰符 + delegate + 返回值类型 + 委托名(参数列表);  
事件: 访问修饰符 + event + 委托名 + 事件名;
委托和事件跟观察者模式联系比较密切,可是我还是没有理解它的精髓,可能是我还太菜了...
总结:灵活运用事件和委托将会给你的程序带来更好的扩展性,这需要丰富经验的积累,好了推荐几篇我曾经学习过的文章把!
     2. C# 中的委托和事件
9.线程
  对于线程学习过,可是一直没有做过多线程的项目,一直没有领悟到它的精髓,也只能停留在表面的高度!
  我就想说下Thread中的后台线程和前台线程(默认为“前台线程”),在这里总结下(其实我也是学习前辈们的知识)。
  前台线程:当所有的前台的线程都执行完毕以后才会退出程序!
  后台线程:对于后台线程,程序是不管你是否是执行完成的,不过当你程序一旦强制退出,后台线程也会终止的!
[url=][/url]

1             Thread thread = new Thread(delegate()2             {3                 Console.WriteLine("线程开始工作");4                 Thread.Sleep(2000);  //暂停两秒钟5                 Console.WriteLine("线程结束");6             });7             thread.IsBackground = true;  //分别设置为true和false,看看控制台运行的情况,我相信你能很快明白的8             thread.Start();9             Console.WriteLine("主线程结束");
[url=][/url]

    总结:设置为后台线程相当于我们说的异步,而前台线程就相当于同步,执行好线程在执行主程序!
  能够熟练使用多线程,还是要在项目中不断的实践,可是项目是可遇而不可求的东西,现在我的项目是肯定要不到了,只能自己看看文章,熟悉熟悉知识啊...
10.六种异步方式
  10.1 委托异步模型     
    使用的是委托的BeginInvoke和EndInvoke异步执行模式!
          必须要有两个条件:
    ① 必须要有个委托作为寄宿体
    ② 执行函数    ExecuteFunction
    ③ 回调函数    CallBackFunction ,所谓的回调函数就是获取执行函数的返回值!
    有了上面三种条件之后,就可以直接调用Begin和End进行委托异步编程了,其中还有细节问题需要注意,下面我们就一一来看!
    具体思路步骤:    
    ① 选择一个适合的委托类型,如参数列表,返回值类型
    ② 创建一个执行函数,必须跟委托的参数列表和返回值类型对应起来
    ③ 创建一个回调函数,它只有一个参数没有返回值,参数类型为IAsyncResult类型,这是使用委托实现异步的规范写法,不可改变
    代码实现:
[url=][/url]

1         //写一段简洁的代码 2         private void button1_Click(object sender, EventArgs e) 3         { 4             //定义委托,并指定异步的执行方法 5             Func<string, string> func = new Func<string, string>(ExecuteFunction); 6      

  14.4 关于注释(书中讲到的注释规则让我很有同感,因为现在项目中就有这样的现象)
    请注意:注释也许真的不需要,学会使用代码就能完整表达设计和逻辑意图!
    常见现象:代码在变动,在演化,彼此分离和重合,可是注释并不总是随着变动,上图:
    
    所以只有代码才能真正的告诉你它在干什么,它有什么作用!
    
    Note:与其花时间编写解释你那糟糕代码的注释,还不如花时间清洁那糟糕的代码!
    坏注释和多余注释的几点原则:
    ①有时候一段坏的注释不紧会影响代码的整洁,而且还会占用一定的时间,最终读注释的时间比阅读代码的时间还长,所以这种注释要删除它,影响我们阅读代码的时间
    ②日志式注释:这种注释最有感触,在class开头写上每次修改的记录,这种方式也有好处,但是这种情况应该在没有源代码控制的情况下进行记录(其实我听赞同在class头上写上每次修改的版本的)
    ③关于废话性和误导性的注释坚决不能存在
    ④能用函数和变量是就别用注释,所以变量和函数的命名真的很重要,可以让人一眼就能看出它的作用
    请明白非常重要的一点:注释的作用就是解释未能自行解释的代码,如果注释本身还需要解释,就太遗憾了!
  14.5 单元测试的重要性
    一直觉得单元测试可有可无,那是因为我只是学习过从来没有真正的在项目中运用过,可是最近我下了狠心要在项目中构建一个单元测试框架,终于被我搞定了,我也感悟到单元测试对一个开发人员的重要性,想学习的话可以看看这篇文章:走进单元测试五:单元测试文章系列目录
  建议大家看看<<代码整洁之道>>和<<.NET设计规范>>以及<<程序猿修炼之道之单元测试>>
15.其它知识点
  15.1 const和readonly本质区别
    理解两者是在“编译时”还是“运行时”常量,以及两者的作用域,那么它们将不会这么神秘!
    编译时OR运行时:
    const:编译时
    readonly:运行时
    作用域:
    const:①本身就是静态变量
        ②只能定义基本类型,如int,string等等
        ③局部变量和全局变量都可以定义
        ④一旦定义就不能修改
    readonly:①不是静态变量,如果需要需加上“static”关键字
          ②可以定义一切类型,可以是自己自定义的对象
          ③只能定义全局变量
          ④一旦定义可以在构造函数里面进行初始化变量
    总结:园子里面还有很多对于它们性能方面的文章,有兴趣的可以搜搜看,推荐使用“readonly”吧!
  15.2 is和as操作符
    16.2.1 As和强制转化最本质的区别      
      As:进行转换的时候永远不是出现异常,当转换失败时会返回一个“null”值,所以你只需要进行一个null值的判断就知道转换失败还是成功了!
             强制转化:会出现转换失败并抛出异常,所以我们都需要使用“try/catch”来捕获转换出错的异常,也可以使用“is”来判断是否是你要转换的类型!
    16.2.2 一些常见注意点
      ① as不能用于值类型的转化
      如:object number=100;int numberOne = number as int;
                 这是因为如果转换失败,那么就会返回一个“null”值,但是值类型是不允许为“null”的,所以在语法上是行不通的,就是你写成了“int?”也是不行的!
      ② 使用Is配合强制转换来进行类型转换
      首先使用“Is”来判断是否是我需要转换的类型,然后在进行强制转换
View Code
        ③ 在没有泛型的foreach中,也是把“object”进行强制转化成所需要的类型,代码如下:
View Code
      Note:或者使用GetType()方法来精确检测是否是你想要的转换类型!
  15.3 运算符操作以及类型转化操作重载
这两个知识点还是比较容易学习的,一个是操作符的重载,一个是用于自定义强制转换的方法(你也可以使用“as”进行强制转换),只要稍加注意一些语法就好了!
[url=][/url]

1     public class MyPerson 2     { 3         public string Name { get; set; } 4  5         /* 6          *  ①必须为静态 7          *  ②关键字operator 8          *  ③需要定义重载的操作符 9          *  ④定义返回值类型10          */11         public static MyPerson operator +(MyPerson personFather, MyPerson personMother)12         {13             return new MyPerson() { Name = personFather.Name + personMother.Name };14         }15 16         /*17             ①必须为静态18          *  ②关键字“explict”和operator”19          *  ③需要转化的类型:MyPerson20          */21         public static explicit operator MyPerson(MyPeople myPeople)22         {23             return new MyPerson(){ Name="YCG" };24         }25     }26     public class MyPeople27     { }
[url=][/url]

  具体的用法如下:
[url=][/url]

1   MyPerson personOne = new MyPerson() { Name = "AAAAAA" };2   MyPerson personTwo = new MyPerson() { Name = "BBBBB" };3   MyPerson personThree = personOne + personTwo;  //操作符重载4   Console.WriteLine(personThree.Name);  5 6   MyPeople people = new MyPeople() { Name = "wang wei" };7   MyPerson personFour = (MyPerson)people; //类型强制转换8   Console.WriteLine(personFour.Name);
[url=][/url]

    15.4 ToString方法
  15.5 数据实体模型(Tuple)以及匿名类型
    16.5.1 Tuple实际上就是一个匿名的实体的模型,它的用处在于不要自己定义一个实实在在的Entity,使用它就能达到效果!
View Code
     Note:在查看源代码的时候注意它的第八个参数:
    
    16.5.2 匿名类型
1 var data = new { number = 11111, str = "ssssss" };  //不需要定义变量的类型,如果想知道匿名类型底层源码怎么写的,可以使用反编译查看源码,一目了然了!2 Console.WriteLine(data.number + data.str);
  15.6 String和StringBuilder详解
    这个技术大妞们已经讨论的很多,我也没这个能力说的一清二楚,推荐几篇文章吧:1. 字符串的驻留(String Interning) 2. 深入理解string和如何高效地使用string 等等,实在很多啦...
17.Remoting
  传送门:.NET Remoting技术文章汇总  ,看过那些文章,对于Remoting的理解会有一个质的上升...

评分

参与人数 2赞扬 +2 收起 理由
妄想丶晴天 + 1 很给力
higoku1 + 1 很给力

查看全部评分

回复

使用道具 举报

Archiver|手机版|小黑屋|开发者网 ( 苏ICP备08004430号-2 )
版权所有:南京韵文教育信息咨询有限公司

GMT+8, 2024-12-23 08:16

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表