C#/.NET 基础学习|C/S开发框架
作者:csframework|C/S框架网  发布日期:2023/02/07 18:11:32

C#/.NET 基础学习|C/S开发框架

初识C#

C#是微软公司发布的面向对象的、运行于.NET Framework之上的高级程序设计语言。与Java有着明显不同,借鉴Delphi的特点,与COM(组件对象模型)直接集成,是微软公司 .NET windows网络框架的主角。
C#是一种语言,.net是一个平台。C#不但可以开发基于.net的应用程序,也可以开发基于WinForm的程序。. net 是 Microsoft 的 XML Web 服务平台,XML Web 服务能使应用程序在 Internet 上传输和共享数据。


 特点:  
  1. 强类型语言,安全稳定;
  2.事件驱动、完全面向对象的可视化编程语言;
  3. 便捷的面向组件编程的支持;
  4. VB简单的可视化操作和C++的高运行效率的结合;
  5. 托管代码和垃圾回收 (garbage collection);


  // .NET ~ C# ~ ASP.NETC#是.net平台下的一种开发语言,用于开发桌面应用程序asp.net是开发web程序的技术 .net是平台,该平台下包含很多技术如:asp.net  ado.net  winform  WCF

 .NET框架
 CLR:公共语言运行库,Common Language Runtime,.NET框架的核心组件,在操作系统的顶层并在运行期调用基类库(BCL, Base Class Library)管理程序的执行。
  · 内存管理机制
  · 垃圾回收机制GC (Garbage Collector)
  · JIT编译器
 CTS:公共类型系统,Common Type System,重要特性是所有类型都继承自公共的基类object。


基础学习

 4个基础命名空间

// .NET框架中的基础类库,用于实现一些基本的类。
using System; .NET应用程序中使用的大多数基本类型
using System.Collections.Generic; 处理集合的泛型类型
using Syatem.Text; 字符串处理和编码相关的类型
using System.Linq; 提供支持使用语言集成查询(LINQ)进行查询的类和接口,用于对集合进行查询

 基础概念
0. 结构 - 类
 struct 是值类型,隐式密封的、不能被继承,但可以实现接口。struct 成员默认是 public,有构造函数(实例、静态),没有析构函数,不允许字段初始化。
 class 是引用类型,单继承,可实现接口。class 成员默认是 private。
  · 数据成员:字段、常量;
  · 函数成员:属性、方法、事件、索引器、构造函数、析构函数、操作符;
1. 字段 - 属性 - 索引
 字段 -private,属性 -public
 属性是指定的一组2个匹配的、称为访问器 (get 和 set) 的方法。属性是函数成员,访问器只能被隐式调用,执行代码,但不为数据存储分配内存。公有属性提供对私有字段的受控访问。
 索引是一组 get 和 set 访问器,类似属性,索引是函数成员;索引通常用于访问多个数据成员,类似数组利用索引运算符;索引不能声明为 static。访问器只能被隐式调用,可以重载,参数列表必须不同。
  · 索引没有名称,但this是必须的;
  · 参数列表中至少必须声明一个参数;

  ReturnType this[参数列表] {get {...}set {...}}

2. 静态构造函数 - (普通的)实例构造函数
 实例构造函数初始化类的每个新实例,static 构造函数初始化类层次的项目。static 构造函数不能访问类的实例成员,通常用于初始化类的静态字段,静态构造函数被系统自动调用。静态字段先于实例成员被初始化,类只能有一个 static 构造函数,不能带参数、不能有访问修饰符、也不能使用 this 访问器。
  [1]. 构造函数中不能调用虚方法;
  [2]. ;
  [3]. ;
3. 继承
 单继承。
 a. 重载:同一个类内的函数,函数名相同、参数列表不同;
 b. 重写(覆盖):父子类之间的函数,签名相同、返回类型相同;父类用 virtual 标识,子类用 override 标识;
 c. 隐藏:默认或通过 new 显式隐藏。base.数据成员/函数名显式访问被隐藏的成员。
    · 字段:名称相同,类型相同; 
    · 函数:签名相同(函数名、参数列表(个数、顺序、类型、修饰符));
4. 抽象类 abstract - 接口 interface
 a. 抽象类可以给出某些成员的一些实现,接口不能包含成员实现;
 b. 抽象类的抽象成员可以被子类部分实现,接口的成员必须被实现类全部实现;
 c. 一个类只能继承一个抽象类(类单继承),但是可以实现多个接口;
 d.类是对对象的抽象,抽象类是对类的抽象,接口是对行为的抽象
 e. 从设计角度,抽象类和接口设计的思维过程不同(相反):
   抽象类 - 自底向上,接口 - 自顶向下;
 - 接口 -
 引用类型,接口可以继承接口,类和结构可以实现接口。接口允许访问修饰符 public、protected、internal、private,接口成员不允许访问修饰符,默认public static。接口声明不能包含数据成员,只能包含属性、方法、事件、索引
 类 A 实现接口 IA,将类 A 的对象引用转换为接口 IA 的引用:
  a. 强制类型转换:IA ia = (IA)objA;但是若类 A 未实现接口 IA,则抛出异常。
  b. as 运算符:IA ia = objA as IA;若类 A 未实现接口 IA,返回 null、不抛出异常。
 实现接口的类可以从它的基类继承实现代码。类实现 2 个接口,2 个接口包含同名方法,类的单一实现就可以满足 2 个接口 或 显式实现每一个接口。同时可以分别获得每一个接口的独立引用。
 
  接口正常实现:接口方法不包含实现代码,实现在类级别的方法中;
  接口显式实现:接口方法包含实现代码,没有类级别的方法;
 :接口的显式实现成员只能被相应的接口引用访问,需要强制转换操作。
5. 密封类 - 抽象类 - 静态类
 a. 密封类:sealed,只能被用作独立的类,不能被继承,可实例化; 
 b. 抽象类:abstract,只能被继承,不可实例化;
 c. 静态类:static,静态类是密封的。不能被继承,不可实例化;
6. 装箱 - 拆箱
 a. 装箱:隐式转换,把值类型打包到Object引用类型的一个实例中;
 b. 拆箱:显式转换,从对象中提取值类型;
 implicit、explicit 和 is、as
 · implicit - 隐式转换,explicit - 显式转换;
   publicstaticimplicit/explicitoperator目标类型(源类型 源类型变量)
 :用户自定义转换仅针对于类和结构。is-as 不能用于用户自定义转换。is-as 不能重载。
 ·is:检查对象类型兼容性并判断能否成功转换,返回bool,不抛出异常;
    适应范围:引用转换、装箱转换、拆箱转换,if(objisType) Type t = (Type)obj;
   as:类似强制转换,检查对象类型兼容性并返回转换结果,不抛出异常,失败时返回null;
    适应范围:引用转换、装箱转换,Type t = objasType; if(null !=t){…}
    true/成功:obj 是 Type 类型或者 obj 是 Type 类型的子类型;
   对于 is,CLR 对对象类型检查了次:is操作首先检查obj是否和Type类型兼容。若兼容,在if语句内执行转换时CLR再检查obj是否为一个Type引用并转换。对于 as,CLR 对对象类型检查了次:as操作检查兼容性并直接转换,效率高、性能好。
 参考:is - as 详解;
7. object sender - EventArgs e
 a. object sender:保存触发事件的对象的引用,指向发送通知的对象;
 b. EventArgs e:EventArgs 是包含事件数据的类的基类,在事件触发时传递数据,但是 EventArgs 不包含任何数据,所有的事件参数类都必须从 EventArgs 类派生;
8. 变体
 变体分为协变 - 抗变两种,针对引用类型:
 a. 协变:covariance,父=子,out,只能用作方法的返回值或属性get的访问器;
 b. 抗变:contravariance,子=父,in,只能用作方法的参数;
9. 可空类型 ? - 空接合运算符 ??
 a. 可空类型允许创建普通值类型的变量并标注其有效性。可空类型是对普通值类型的 private 封装,其问号语法是通过 System.Nullable<T> 利用泛型实现,与普通值类型可以相互转换。不能创建引用类型的可空类型。2 个只读属性:
 -HasValue:bool 类型,标识是否有效; 
 -Value:变量值;(普通值类型的值、可空类型的值、null
 b. 空接合运算符允许在可空类型的变量为 null 时返回一个给定值。 
10. 泛型
 类型是实例对象的模板,泛型类型是类型的模板。
 类型参数的约束用where子句列出:where 参数:constraint, constraint, …
 · 构造函数约束 new() 必须放在最后;
 · 主约束(class/struct)至多一个,且必须放在第一位; 
 · 接口约束可以有多个;
 只有 Type 类型或派生于 Type 类型的实参才能用于受约束的参数。 
 
委托-事件
 a. 委托 delegate:对函数的封装,一种引用方法的类型 (引用类型),代表一类方法,具有相同参数列表和返回类型;
 b. 事件 event:委托的一种特殊情形,事件的类型是委托,事件是委托类型的变量,事件不是类型,事件是成员(变量)且被隐式自动初始化为null;
  利用”+=”增加委托的实例/静态方法,利用”-=”移除委托的实例/静态方法。事件被触发时,执行被委托的方法(调用委托来依次调用调用列表中的方法)。此处引用大话设计模式中的例子:
  publicdelegatevoid CatShoutEventHandler(object sender, EventArgs e);
  publiceventCatShoutEventHandler CatShout;
  委托是面向对象、类型安全的并且是可靠受控、安全的。当委托被调用时,它调用有序方法列表中的每一个方法。委托是恒定的,委托对象被创建后就不会再被改变。调用空委托会抛出异常,通过把委托和null比较判断委托的调用列表是否为空,进而判断委托是否为null。
 泛型委托
  publicdelegateTRFunHandler<T1,T2,TR>(T1p1,T2p2)
 匿名方法 -> Lambda表达式
  匿名方法,anonymous method,可以避免创建使用独立的具名方法,允许在创建并初始化委托或为委托增加方法时包含小段的内联inline代码。
    delegate(参数列表){语句块};
  Lambda表达式避免冗余信息、简化匿名方法的语法。
 总结: 从 委托事件 到 观察者模式;
 
扩展方法
 允许向现有类型"添加"方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。类A需要新增一个方法,但类A是密封的或源代码不可见,即不能修改类A,此时扩展方法允许在另一个类B中利用类A的公有可用成员实现类A需要新增的方法。
 · 扩展方法必须是静态的,所在类也必须是静态的;
 · 被扩展类型必须作为第一个参数,必须用 this 修饰; 
 publicstaticclass ExtendMyClass {
   publicstatic返回类型 Function(thisMyClass mc) {
      // 调用MyClass的公共成员实现新增方法
   }
 }
 调用:mc.Function();,如果没有this,只能以ExtendMyClass.Function(mc);方式调用。
 扩展方法还可以结合泛型类,允许将(扩展)类中的静态方法关联到不同的泛型类上。扩展接口时,利用扩展方法比继承接口(会强制要求实现接口下的所有方法)更方便。但是,扩展方法的优先级总是比被扩展类型本身中定义的同名实例方法低,且被扩展类型的子类不能继承其父类型的扩展方法。
 · 将静态方法转成扩展方法,扩展方法本质上是静态方法;
 · 编写帮助类;
 · 为 Linq 服务,实现链式编程;
 参考:谈扩展方法的理解; C#扩展方法;
    奇思妙想之扩展方法系列;
 
枚举~枚举数~可枚举类型
 枚举 enum,值类型,成员是整数值常量,可以显式为其赋值初始化,但不能使用修饰符。枚举可用于实现位标志,注意添加 [Flags] 特性。
 可枚举类型是实现了GetEnumerator()方法的类型,返回用于(读取并返回)集合中数据项的枚举数,枚举数是可以依次返回集合中数据项的类对象。
 参考:迭代器学习系列;自定义类实现foreach;
 [-1-].IEnumerable/IEnumerator
  非泛型枚举数和可枚举类型,枚举数类通常声明为类中的嵌套类。
  ·IEnumerator
  -Current:当前位置对应的数据项;
  -MoveNext():下移位置,初始位置为-1;
  -Reset():复位;
  ·IEnumerable
  -IEnumerator GetEnumerator(): 
 [-2-].IEnumerable<T>/IEnumerator<T>
  泛型枚举数和可枚举类型,类型安全。
 总结:IEnumerable / IEnumerator 学习 - sqh  
   
 某些重要的关键字/修饰符/运算符
0. object 类
 C#中所有的类(型)都直接/间接继承自System.Object类(型),值类型数据可以隐式转换为Object类型;object是引用类型,关键字object就是System.Object的别称。
 静态方法 
 [1]. publicstaticboolEquals(object objA, object objB){}
   调用实例方法Equals(object obj),判断是否相等;
 [2]. publicstaticboolReferenceEquals(object objA, object objB){}
   判断两个对象是否引用相等;
 实例方法
 [1]. publicvirtualboolEquals(object obj){}
   方法需要重写用于实现根据值来判断对象是否相等;
 [2]. publicvirtualintGetHashCode(){}:获取对象的Hash值;
 [3]. public TypeGetType(){}
   获取当前实例的Type,查询对象的元数据来确定对象的运行时类型;
 [4]. publicvirtualstringToString(){}:获取当前实例的字符串信息,对象的字符串表达形式;
 受保护方法
 [1].protectedvirtual void Finalize(){}
   类或派生类可以访问,允许 Object 在“垃圾回收”机制回收 Object 之前尝试释放资源并执行其他清理操作;
 [2].protectedobject MemberwiseClone(){}:创建当前实例的浅表副本;
1. partial
 a. 把类定义放在多个代码文件中;
 b. 用于创建部分方法(定义声明和方法实现),不能有访问修饰符,返回值必须为 void;
2. internal
 类和类成员的访问修饰符,同一程序集权限。类默认是 internal,类成员默认是 private。
 protected internal:受保护的内部成员,同一程序集or子类权限。
 参考:internal - 举例参考
 嵌套类:嵌套是指类声明的位置,而不是类实例的位置。
 嵌套类具有成员访问级别,默认 private,可见性具体地:
  · 嵌套类型的成员对封闭类型的成员具有完全访问权限;
  · 封闭类型的成员只能访问嵌套类型的public和internal成员,不能访问private和protected成员;
 嵌套类型的对象访问封闭类型,需要维护封闭类型的引用。
3. using
 a. using 指令:命名空间指示符
 b. using 别名:类型别名指示符
  一个.cs文件引用了两个不同的命名空间,但两个空间都包括一个相同名字的类型,使用别名更简洁。
  using aClass = NameSpaceA.MyClass;
  using bClass = NameSpaceB.MyClass;
 c. using语句:资源的包装和管理 -> 隐式的 try…finally 块
  定义一个范围,在范围结束时自动处理对象,自动调用这个类实例的 Dispose 方法。资源是一个实现 System.IDisposable 接口的类或结构。
4. 异常try…catch…finally
 结构化异常处理语法,标记出能处理异常的代码和指令:
  ■  try:包含可能会抛出异常的代码;
  ■  catch:抛出异常后要执行的代码,catch块可多个;
  ■  finally:始终一定会执行的代码,释放资源;
 try 块是必须的,catch 和 finally 必须至少有一个。所有的异常类均派生于 System.Exception 类。
 异常嵌套的处理:如果异常出现在 Method2 方法内部,但是其 catch 块没有匹配的异常处理程序, 系统沿着调用栈向上搜索到 Method1,如果找到匹配的 catch 块,系统先回到栈顶 Method2 处执行其 finally 块,然后把 Method2 从调用栈中 pop(),最后执行 Method1 的相应 catch 块和 finally 块。

 public void Method2()                    public void Method1()     {                                         {try{                                      try{...                                       Method2();}                                         }catch{...}                                catch{...}finally{...}                               finally{...}}                                         }

  ■  throw:显式抛出异常;
  -throwException;异常抛出后,异常实例可以被 catch 块捕获。
  -throw;此种只能在 catch 块内,捕获后再重新抛出。
5. String、StringBuffer 与 StringBuilder
 String是字符串常量、定长,StringBuffer与StringBuilder是字符串变量、可变长、避免产生额外的临时变量;StringBuffer线程安全,StringBuilder是非线程安全,三者的执行速度 StringBuilder > StringBuffer > String。具体区别详见:
 参考: String - StringBuffer - StringBuilder.
 string - String
 String是.NET Framework中的类,string是C#中的类,C#的string映射为.NET Framework的String;string是C#中的关键字,可以作为String或System.String的别名;
6. const 与 readonly
 const只能在声明语句中初始化,readonly可以在声明语句或构造函数中初始化,const是编译时常量、在内存中没有存储位置,readonly是运行时常量、在内存中有存储位置;const是静态的,readonly可以是静态字段也可以是实例字段。
7. typeof 与 GetType
 typeof:一元运算符,返回作为它的参数的任何类型的 System.Type 对象,不能重载。
 GetType:方法,可以调用 typeof 运算符,对任意类型的任意对象都有效。
8. var
 推断类型,弱化类型的定义,可替代任何类型,但是 var 并不改变 C# 强类型性质。类似object,但object是引用类型,效率比var低。
 var 用于本地局部变量,不能用于字段,使用时必须初始化且不能再次赋类型不同的值;
 

 常用函数
1. Convert.ToInt32 - int.Parse(Int32.Parse)- int.TryParse - (int)
 a. Convert.ToInt32与int.Parse类似,Convert.ToInt32 内部调用了int.Parse,Convert.ToInt32 可以转换的类型较多,int.Parse只能转换数字类型的字符串;


 b. int.TryParse与int.Parse类似,但不会抛出异常,返回值为bool以指示解析是否成功,从而可以免去添加异常处理代码的麻烦,out参数为转换输出值;
 此四者都可以解释为将类型转换为 int,eg:举例参考.
 :所有预定义的简单类型均包含静态方法 Parse,将字符串解析为相应的数据值。
2. Split
 String类的内置方法,分割函数,参数可以为单个字符、多个字符、字符串。
 参考:Split - 常用举例参考,Split的不同重载方法.
3. Trim
 String类的内置方法,用于去除字符串前后的指定字符,另外还有TrimStart()和TrimEnd()方法。
 参考:Trim - 举例参考.
4. DateTime
 · 与字符串string的转换
  - DateTime.Parse(timeString);
  - Convert.ToDateTime(timeString);
  - if (DateTime.TryParse(timeString, out datetime)) {
     DateTime dm = datetime;
   }
 · DateTime
 
x. xxx


集合类数据存储和检索

命名空间:using System.Collections;
     using System.Collections.Generic;
ArrayList对应的泛型集合是List,与HashTable对应的泛型集合是Dictionary
 -ArrayList:是Array的复杂版本,动态数组,实现了ICollection和IList接口,针对任意类型、任意长度,非类安全型的;
  声明:ArrayList mAList = new ArrayList();
  具体地属性方法类似List,此处不再赘述。 
 -HashTable:每个元素都是一个存储在DictionaryEntry对象中的键值对。keyvalue键值对均为object类型,支持任何类型的keyvalue键值对,非类安全型的;线程安全的;
  声明:Hashtable ht = new Hashtable();
  遍历哈希表元素:
   foreach(DictionaryEntry de in ht)
  哈希表排序:
   ArrayList KeysAList = new ArrayList(ht.Keys);
   KeyAList.Sort();
1. 泛型List
 声明:List<T> mList = new List<T>();
 属性方法:
  - mList.Count:对链表mList元素计数
  - mList.Add(T item):添加元素
  - mList.Insert(int pos, T item):指定位置插入元素
  - mList.AddRange(List list):链接2个List
  - mList.Contains(T item):测试List是否包含元素item
  - mList.Item(int idx):索引器,通过指定索引获取或设置元素
  - mList.Remove(T item):删除指定的元素
  - mList.RemoveAt(int pos):删除指定位置的元素(推荐)
  - mList.RemoveRange(int b, int n):删除从b开始的n个元素
  - mList.Clear():清空List
  - mList.Reverse():反转List
  - mList.Sort():排序List
2. 泛型Dictionary
  在C#中,Dictionary提供快速的基于键值的元素查找。Dictionary<[key], [value]>,键必须唯一且不能为空引用null,值若为引用类型则可以为空。
 声明:Dictionary<T1, T2> mDict = new Dictionary<T1, T2>();
 属性方法:
  - mDict.Count:对字典mDict元素计数
  - mDict.Add(T1 key, T2 value):添加元素(键, 值)对
  - mDict.ContainsKey(T1 key):字典是否包含键为key的元素
  - mDict.ContainsValue(T2 value):字典是否包含值为value的元素
  - mDict.Remove(T1 key):移除键为key的元素
  - mDict.Clear():清空Dict
  - 遍历字典元素
    1. By KeyValuePair
     foreach (KeyValuePair<T1, T2> kvp in mDict) 或 foreach(var kvp in mDict)
    2. By Key
     Dictionary<T1, T2>.KeyCollection keyCol = mDict.Keys;
     foreach (T1 key in keyCol)  或  foreach(T1 key in mDict.Keys) 
    3. By Value
     Dictionary<T1, T2>.ValueCollection valueCol = mDict.Values;
     foreach (T2 value in valueCol)  或  foreach(T2 value in mDict.Values)
  - mDict[key] = value:通过索引器读写键值对
  - mDict.TryGetValue(T1 key, out value_T2):获取与指定的键相关联的值。通过键取值,包括两个参数,一个是要查询的键,另一个是获取的值,注意值前面使用out关键字。
  注:“判断键存在”和“根据键取值”两步转化为一步,键的哈希值只计算一次,效率高。
 以下三个集合类,可以进一步参考Stack - Queue - SortedList.
3. SortedList
 System.Collections.SortedList类表示按键排序的键/值对的集合,可以按键或索引访问,是数组和哈希表的组合。
 声明:SortedList sList = new SortedList();
 遍历排序列表元素:
  foreach(DictionaryEntry de in sList)
 -泛型SortedList
 
4. 堆栈 Stack
 System.Collections.Stack类表示对象的LIFO集合,处理顺序多变。
 声明:Stack st = new Stack();
 属性方法:
  - st.Peek:取栈顶元素,但不将其移除;
  - st.Push(object obj):栈顶入栈;
  - st.Pop():出栈,移除并返回位于Stack栈顶处的对象;
 -泛型Stack

5. 队列 Queue
 System.Collections.Queue类表示对象的FIFO集合,顺序处理集合中的对象。
 声明:Queue qu = new Queue();
 属性方法:
  - qu.Peek:取队首元素,但不将其移除;
  - qu.Enqueue(object obj):队尾入队;
  - qu.Dequeue():出队,移除并返回位于Queue开始处的对象;
 -泛型Queue
 
 当有多个线程并发访问集合时,应该用System.Collections.Concurrent命名空间代替上述命名空间中的对应类型,线程安全的集合类可由多个线程同时访问:
 -ConcurrentDictionary
 
 -ConcurrentQueue

C/S框架网|原创精神.创造价值.打造精品


扫一扫加作者微信
C/S框架网作者微信 C/S框架网|原创作品.质量保障.竭诚为您服务
上一篇 下一篇