zoukankan      html  css  js  c++  java
  • C#/.NET 基础学习

    与 Java有不同,借鉴 Delphi的特点,与 COM(组件对象模型)直接集成,是 .NET windows网络框架的主角。 

    C#是一种语言,.net是一个平台。

    C#不但可以开发基于.net的应用程序,也可以开发基于WinForm的程序。

    . Net 是 Microsoft 的 XML Web 服务平台,XML Web 服务能使应用程序在 Internet 上传输和共享数据。   

    特点

    • 强类型语言,安全稳定;
    • 事件驱动、完全面向对象的可视化编程语言;
    • 便捷的面向组件编程的支持;
    • VB简单的可视化操作和C++的高运行效率的结合;
    • 托管代码和垃圾回收 (garbage collection);
    // .NET ~ C# ~ ASP.NET
    C#是.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]. 构造函数初始化器关键字:this,base,控制类中构造函数的执行顺序
    [3]. 静态构造函数只会被执行一次(在创建第一个实例或引用任何静态成员之前,且由.NET自动调用)
    [4]. 静态构造函数在程序域(AppDomain)的层级确保只会执行一次,且线程安全
    [5]. 静态构造函数非常适于在单件模式中(或只需要单一对象的地方)

    关于两者的具体信息参见:http://www.cnblogs.com/jiagoushi/p/3775046.html
    3. 继承
    单继承。
    a. 重载:同一个类内的函数,函数名相同、参数列表不同;
    b. 重写(覆盖):父子类之间的函数,签名相同、返回类型相同;父类用 virtual 标识,子类用 override 标识;
    c. 隐藏:默认或通过 new 显式隐藏。base.数据成员/函数名 显式访问被隐藏的成员。

    • 字段:名称相同,类型相同; 
    • 函数:签名相同(函数名、参数列表(个数、顺序、类型、修饰符));

    4. 抽象类 abstract - 接口 interface (抽象类 - 自底向上,接口 - 自顶向下)

    • 抽象类可以给出某些成员的一些实现,接口不能包含成员实现;
    • 抽象类的抽象成员可以被子类部分实现,接口的成员必须被实现类全部实现;
    • 一个类只能继承一个抽象类(类单继承),但是可以实现多个接口;
    • 类是对对象的抽象,抽象类是对类的抽象,接口是对行为的抽象
    • 从设计角度,抽象类和接口设计的思维过程不同(相反):

    接口
    引用类型,接口可以继承接口,类和结构可以实现接口。

    接口允许访问修饰符 public、protected、internal、private,接口成员不允许访问修饰符,默认 public static

    接口声明不能包含数据成员,只能包含 属性、方法、事件、索引
    类 A 实现接口 IA,将类 A 的对象引用转换为接口 IA 的引用:

    • 强制类型转换:IA ia = (IA)objA;但是若类 A 未实现接口 IA,则抛出异常。
    • as 运算符:IA ia = objA as IA;若类 A 未实现接口 IA,返回 null、不抛出异常。

    实现接口的类可以从它的基类继承实现代码。类实现 2 个接口,2 个接口包含同名方法,类的单一实现就可以满足 2 个接口 或 显式实现每一个接口。同时可以分别获得每一个接口的独立引用。

    • 接口正常实现:接口方法不包含实现代码,实现在类级别的方法中;
    • 接口显式实现:接口方法包含实现代码,没有类级别的方法;

    :接口的显式实现成员只能被相应的接口引用访问,需要强制转换操作。
    5. 密封类 - 抽象类 - 静态类

    • a. 密封类:sealed,只能被用作独立的类,不能被继承,可实例化; 
    • b. 抽象类:abstract,只能被继承,不可实例化;
    • c. 静态类:static,静态类是密封的。不能被继承,不可实例化;

    6. 装箱 - 拆箱

    • a. 装箱:隐式转换,把值类型打包到Object引用类型的一个实例中;
    • b. 拆箱:显式转换,从对象中提取值类型;

    implicitexplicitisas

    [1]. implicit - 隐式转换,explicit - 显式转换;

    public static implicit/explicit operator 目标类型(源类型 源类型变量)
    :用户自定义转换仅针对于类和结构。is-as 不能用于用户自定义转换。is-as 不能重载。 

    [2]. is:检查对象类型兼容性并判断能否成功转换,返回bool,不抛出异常;

    • 适应范围:引用转换、装箱转换、拆箱转换,if(obj is Type) Type t = (Type)obj; 

    [3]. as:类似强制转换,检查对象类型兼容性并返回转换结果,不抛出异常,失败时返回null;

    • 适应范围:引用转换、装箱转换,Type t = obj as Type; 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 封装,与普通值类型可以相互转换。 Type ? nullableType; 其问号语法是通过 System.Nullable<T> 利用泛型实现,? 是System.Nullable<T>的缩写

    针对值类型,不能创建引用类型的可空类型。2个只读属性:
     -HasValue:bool 类型,标识是否有效; 
     -Value:变量值;(普通值类型的值、可空类型的值、null
    b. 定义可空类型和引用类型的默认值,允许在可空类型的变量为 null 时返回一个给定值。单元运算符,左右两边数据类型必须相同或能隐形转换,右结合运算。首先检测左边的值,若为Null,则整个表达式取值为右侧的值,否则为左侧的值。

    • string str = null; Console.Write(str ?? "abc"); 将输出:"abc"
    • string str = "s"; Console.Write(str ?? "abc"); 将输出:"s"
    • a??b??c == a??(b??c)
    10. 泛型
    类型是实例对象的模板,泛型类型是类型的模板。
    类型参数的约束用 where 子句列出:where 参数:constraint, constraint, …
    • 构造函数约束 new() 必须放在最后;
    • 主约束(class/struct)至多一个,且必须放在第一位; 
    • 接口约束可以有多个;
    只有 Type 类型或派生于 Type 类型的实参才能用于受约束的参数。
    11. 字符串
    规则字符串:在双引号中的零个或多个字符组成,并且可包含简单转义字符序列。("str")
    逐字字符串:由 @ 字符后跟普通的双引号字符串。(@"str")
    • 将 当作 普通字符 处理、而非转义字符,但局部有效性(@"xxxabc" + "\");
    • 可任意换行(常用于SQL字符串),但是换行符、缩进、空格都计算在字符串长度之内;
    • 在str中,用两个连续的英文双引号表示一个英文双引号(注意是必须在str中);
    :C#中Environment.NewLine表示为当前环境定义的换行字符串(非Unix平台为字符串“ ”,Unix平台为字符串“ ”),推荐使用。 
    IsNullOrEmpty:判断字符串是否为null或者string.Empty;
    IsNullOrWhiteSpace:判断字符串是否为null、空(string.Empty)还是仅由空白字符组成;
    首先,确认string.Empty为空字符串,即string.Empty = "";对于" "、" "这样的仅由空白字符组成的字符串,IsNullOrWhiteSpace可以直接判定,而IsNullOrEmpty需要str.Trim().Length搭配使用。

    委托 - 事件

     a. 委托 delegate:对函数的封装,一种引用方法的类型 (引用类型),代表一类方法,具有相同参数列表和返回类型;
     b. 事件 event:委托的一种特殊情形,事件的类型是委托,事件是委托类型的变量,事件不是类型,事件是成员(变量)且被隐式自动初始化为null;
      利用”+=”增加委托的实例/静态方法,利用”-=”移除委托的实例/静态方法。事件被触发时,执行被委托的方法(调用委托来依次调用调用列表中的方法)。此处引用大话设计模式中的例子:
      public delegate void CatShoutEventHandler(object sender, EventArgs e);
      public event CatShoutEventHandler CatShout;
    委托是面向对象、类型安全的并且是可靠受控、安全的。

    • 当委托被调用时,它调用有序方法列表中的每一个方法。委托是恒定的,委托对象被创建后就不会再被改变。
    • 调用空委托会抛出异常,通过把委托和null比较判断委托的调用列表是否为空,进而判断委托是否为null。

    匿名方法 -> Lambda表达式
    匿名方法,anonymous method,可以避免创建使用独立的具名方法,允许在创建并初始化委托或为委托增加方法时包含小段的内联inline代码。
      delegate(参数列表){语句块};
    Lambda表达式避免冗余信息、简化匿名方法的语法。
    总结从 委托事件 到 观察者模式;  

    枚举 ~ 枚举数 ~ 可枚举类型

    枚举 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]. public static bool Equals(object objA, object objB){}
       调用实例方法Equals(object obj),判断是否相等;
     [2]. public static bool ReferenceEquals(object objA, object objB){}
       判断两个对象是否引用相等;
    ■ 实例方法
     [1]. public virtual bool Equals(object obj){}
       方法需要重写用于实现根据值来判断对象是否相等;
     [2]. public virtual int GetHashCode(){}:获取对象的Hash值;
     [3]. public Type GetType(){}
       获取当前实例的Type,查询对象的元数据来确定对象的运行时类型;
     [4]. public virtual string ToString(){}:获取当前实例的字符串信息,对象的字符串表达形式;
    ■ 受保护方法
     [1]. protected virtual void Finalize(){}
       类或派生类可以访问,允许 Object 在“垃圾回收”机制回收 Object 之前尝试释放资源并执行其他清理操作;
     [2]. protected object 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:显式抛出异常;
    throw Exception;异常抛出后,异常实例可以被 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:一元运算符, typeof(classA) 返回作为它的参数的任何类型的 System.Type 对象,不能重载。
    • GetType:System.Object的方法, obj.GetType(); 可以调用 typeof 运算符,对任意类型的任意对象都有效。

    8. Marshal.SizeOf和sizeof

    参考:http://www.cnblogs.com/jxnclyk/archive/2010/06/09/1754438.html,同时考虑内存对齐的问题,特别是结构体中包含引用对象时,最好使用Marshal.SizeOf。

    常用函数

    1. Convert.ToInt32 - int.Parse(Int32.Parse)- int.TryParse - (int)
    • Convert.ToInt32与int.Parse类似,Convert.ToInt32 内部调用了int.Parse,Convert.ToInt32 可以转换的类型较多,int.Parse只能转换数字类型的字符串;
    • int.TryParse与int.Parse类似,但不会抛出异常,返回值为bool以指示解析是否成功,从而可以免去添加异常处理代码的麻烦,out参数为转换输出值;
    此四者都可以解释为将类型转换为 int,eg:举例参考.
    :所有预定义的简单类型均包含静态方法 Parse,将字符串解析为相应的数据值。
    2. Split
    String类的内置方法,分割函数,参数可以为单个字符、多个字符、字符串。
    参考Split - 常用举例参考Split的不同重载方法.
    3. CompareOrdinal:(推荐
    将整个字符串每5个字符(10个字节)分成一组,然后逐个比较,找到第一个不相同的ASCII码后退出循环,并求出两者的ASCII码差。虽然实现麻烦,但在CLR via C#上有表明:该方法比其他方法都要快。
    4. DateTime
    · 与字符串string的转换
    - DateTime.Parse(timeString); 
    - Convert.ToDateTime(timeString); 
    - if (DateTime.TryParse(timeString, out datetime)) { 
         DateTime dm = datetime; 
       } 
    · DateTime

    集合类数据存储和检索

    ArrayList 对应的泛型集合是 List,与 HashTable 对应的泛型集合是 Dictionary
    ArrayList:是Array的复杂版本,动态数组,实现了ICollection和IList接口,针对任意类型、任意长度,非类安全型的;
    具体地属性方法类似List,此处不再赘述。 
    HashTable:每个元素都是一个存储在DictionaryEntry对象中的键值对。keyvalue键值对均为object类型,支持任何类型的keyvalue键值对,非类安全型的;线程安全的;
    遍历哈希表元素: foreach(DictionaryEntry de in ht)
    哈希表排序:

    ArrayList KeysAList = new ArrayList(ht.Keys); 
    KeyAList.Sort(); 

    1. 泛型List

     - 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,值若为引用类型则可以为空。

     - 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类表示按键排序的键/值对的集合,可以按键或索引访问,是数组和哈希表的组合。
    遍历排序列表元素:foreach(DictionaryEntry de in sList)
    泛型SortedList

    4. 堆栈 Stack
    System.Collections.Stack类表示对象的LIFO集合,处理顺序多变。

    st.Peek:取栈顶元素,但不将其移除; 
    st.Push(object obj):栈顶入栈; 
    st.Pop():出栈,移除并返回位于Stack栈顶处的对象;

    泛型Stack

    5. 队列 Queue
    System.Collections.Queue类表示对象的FIFO集合,顺序处理集合中的对象

    qu.Peek:取队首元素,但不将其移除; 
    qu.Enqueue(object obj):队尾入队; 
    qu.Dequeue():出队,移除并返回位于Queue开始处的对象; 

    泛型Queue

    集合与多线程

    当有多个线程并发访问集合时,应该用System.Collections.Concurrent命名空间代替上述命名空间中的对应类型,线程安全的集合类可由多个线程同时访问:
    • ConcurrentDictionary
    • ConcurrentQueue
    • ConcurrentBag

    有关集合类的详细内容参见:http://www.cnblogs.com/wjcx-sqh/p/6049314.html

    参考:[1]. 经典.Net面试题; [2]. .Net面试题系列 0-9

  • 相关阅读:
    FastJson中JSONObject用法
    复盘项目模板
    java Enum 类型
    Java List集合总结
    Spring boot 使用Slf4j 日志
    java.lang.reflect.UndeclaredThrowableException
    Intellij IDEA 中使用 Debug
    Java 13位时间戳转换日期格式
    Java 时间格式转换
    Spring boot 自定义注解
  • 原文地址:https://www.cnblogs.com/wjcx-sqh/p/5929901.html
Copyright © 2011-2022 走看看