C# 语言基础

  1. C# 语言基础

C# 语言基础

.NET 一个运行库和一个全面的基础类库。

.NET Framework

NET 平台主要有几三个构造块组成,如下:

  • CLR Common Language Runtime,表示的是公共语言运行库。
    CLR 的主要作用是为我们定位、加载和管理.NET 类型,同时也负责一些低层细节的工作,如内存管理、应用托管、处理线程、案例检查等。

  • CTS Common Type System,表示公共类型系统。
    CTS 完整描述了运行库所支持的所有可能的数据类型和编程结构,指定了这些实体间如何交互、也规定了它们在 .NET 元数据格式中的表示(关于元数据,可以从网上获取参考资料)。

  • CLS Common Language Specification,它表示的是公共语言规范。
    CLS 定义了一个让所有 .NET 语言都支持的公共类型和编程结构的子集。这样,如果构造的 .NET 类型仅公开与CLS兼容的类型,那么可以肯定其他所有支持 .NET 的语言都能使用他们。反之,如果使用了不兼容的,就不能交互。

文档注释:符号是3条斜线“///”,定在类、方法或属性的前面。

数组的静态初始化
使用静态初始化时,数组的声明与初始化必须放在同一条语句中,不能分开写;如:
  int[] ages = { 20, 21, 25, 28, 30 } ;

数组的动态初始化
声明与初始化可以分开或一起写 数组名 = new 数组类型[长度] 自动分配默认值
int[] ages = new int[5] { 20 , 22 , 24 , 26 , 30 } ;

foreach 是一种更简单更明了的读取数组元素的语句。
特点:
—用于读取容器类数据(数组、集合等)
— 适合一次性读取全部元素
—不能修改元素
foreach( 数据类型 变量名 in 数组名)
{
//变量名此时表示的就是数组中的每一个元素
}

二维数组
数据类型[,] 数组名 = new 数据类型[行数,列数]

参数修饰符

  • out修饰符
    定义为带有输出参数(通过关键字out)的方法有义务在退出这个方法之前,给参数赋一个恰当的值(如果不这样做,会出现编译错误)调用该方法时,也需要使用out修饰符
    允许传递未分配(未初始化)的数据
    通过它,调用者只使用一次方法调用就能获得多个返回值。
1
2
3
4
static void Add(int x, int y, out int addValue, out int subValue){
addValue = x + y;
subValue = x - y;
}
  • ref修饰符
    输出参数不需要在它们被传递给方法前初始化,因为方法在退出之前必须为输出参数赋值。
    引用参数必须在它们被传递给方法之前初始化,因为是在传递一个对已存在变量的引用。如果不赋给它初始值,就相当于木对一直未赋值的本地变量进行操作。

方法重载
在同一个类的一组方法(至少大于或等于两个方法)
这些方法的方法名称相同,参数类型或参数个数不同
能否构成方法的重载,跟方法的返回值没有关系

  • protected
    一般用于含有继承关系的子父类当中。可以由定义它们的类型及其任意子类使用,但外部类无法通过 C# 的“.”操作符访问。

  • internal:内部的
    用于修饰:类型或者类型成员
    作用范围:当前项目下的所有类
    使用internal修饰类中的字段或方法,在当前项目所有类下都可访问,但是其它项目是访问不到的。

  • protected internal :受保护的内部的
    用于修饰:类型成员或者嵌套类型 
    如果使用了 protected internal 关键字,作用范围在定义它们的程序集、类以及派生类中可用。

封装性

  • 广义封装
    更多的是从整个项目的项目架构设计上考虑的,比如说完成一个项目时,该项目有几个模块组件,每个模块应该包含哪些对象,对象与对象之间的关系,模块与模块之间的关系划分等,这些可以使用广义封装解决

  • 狭义封装
    对象的内部数据不应该从对象实例直接访问。对象数据应该被定义为私有的,如果调用者想改变对象的状态,就要间接使用公共成员。
    狭义封装,表示的是是对一个类中的成员(字段、方法等)的访问权限(作用范围)进行的一种限制操作。
    通常情况下,使用C#中的访问控制符(又叫访问修饰符)来修饰类中的字段和方法的作用范围,是目前实现狭义封装的一种方式。

    1. 创建完一个类后,类中的字段使用 private 修饰,类中的方法使用 public 修饰;
    2. 为类中用 private 修饰的字段添加一组方法,以保证既能保护类中的字段不被任何赋值修改,又可在外界必须访问这些字段时,提供一种间接访问方式;
    3. 说明:这组间接的访问方法叫做:Get和Set方法。
  • 标准属性
    基本语法:

    1
    2
    3
    4
    5
    [访问修饰符]   数据类型  属性名
    {
    get { return  字段名; }
    set { 字段名 = value ; }
    }

    注意事项:
    访问修饰符,一般都是使用 public
    数据类型,就是当前操作的字段的类型
    属性名,就是当前操作的字段名(使用Pascal命名法)。

    标准属性基本特点:
    一个字段通常对应一个属性,属性的类型应与当前字段定义时的类型保持一致;
    一个属性中包含一组方法 , get用于获取字段值 , set 用于为字段赋值,赋值时系统存在一个隐式变量,为value 在为字段赋值时,业务逻辑处理的代码,也是放在set中的;
    属性本身不保存任何数据,访问字段为字段赋值等操作,看似操作的是属性,实质对数据的访问设置还是对字段的操作,且是由这两个方法实现;
    标准属性,可设置只读 | 只写属性 ,只读权限时只保留get 方法即可;只写权限时只保留 set 方法即可;即可读又可写权限时 get 和 set 都要保留。
    对象.属性 = xxx 时会将xxx自动传给隐式变量value set中可判断value的取值范围,满足要求再传给属性字段

  • 自动属性
    当属性(又叫属性访问器)中不需要任何其他逻辑时(即不需要在set方法中添加任何业务代码)使用自动属性可以更加简洁。
    自动属性本质就是一个字段两个方法。
    语法:[访问修饰符] 数据类型 属性名 { get ; set ; }

    自动属性特点:
    自动属性可利用编译器自动生成,以简化代码的编写注:代码中输入prop,按两下Tab键即可自动生成;
    自动属性只能成对出现,即:不能只有一个get或一个set,也就是,自动属性不支持设置 只读 | 只写 操作;
    自动属性不支持在 set 中添加业务逻辑代码;
    编译器在生成自动属性时,会自动添加一个私有的字段,我们在写时,不用再自己声明私有字段,只需要直接添加属性即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public int name{
    get;
    set;
    }
    //等价于
    private int name;
    public int Name{
    get;set;
    }

继承性
单继承,即:一个子类只能有一个直接父类(继承的单层性);
编译器是先进入到父类中,调用父类无参数的构造方法,如果父类没有无参数构造方法,编译器会自动为父类添加无参数,执行完父类无参数后,再执行子类自己的构造方法
如果父类有其它形式构造方法,但是没有无参数的构造方法,此时程序会报错。

  • base
    访问父类中的同名方法,适合于子类中存在与父类相同签名的方法时;
    访问父类的构造方法,在子类构造方法的小括号后面使用 : base( 参数值列表 ) 表示访问父类的构造方法;
    子类构造方法小括号后面默认省略 :base()

多态性
父类变量,创建子类对象
基本语法:
  父类 变量名  =  new  子类(参数列表)
向上转型
在执行期间判断对象的类型,决定执行子类还是父类的方法的机制称之为动态绑定。
当子类和父类都有相同的方法时,调用子类自己的方法;
当子类没有该方法时,调用父类的方法;
当子类和父类都没有调用的方法时,程序编译报错。
应用:

  • 多态在数组方面的应用
    多态数组
    创建Car类的数组,可放不同子类的对象,并override不同子类的方法,自动识别
  • 多态特性作用于方法的参数上
    方法参数多态
    定义方法的参数类型时,要求参数既可以接收多种子类型,此时就可以将参数的类型定义为父类型,而运行时会根据传递过来的参数类型具体匹配。

  • 多态特性作用于方法的返回值上

Static

  • 静态成员变量
    静态成员变量属于类,类被加载时初始化,且只有一份。
    特点:存在优先于对象,被所有对象所共享,常驻内存。
  • 静态构造函数
    初始化类的静态数据成员。
    仅在类被加载时执行一次。
    不允许使用访问修饰符。
  • 静态方法
    通过引用调用实例方法时,会隐式的传递对象引用,以便在方法内部可以正确访问该对象成员变量。
    通过类名调用静态方法时,因为没有具体对象,所以在static方法中不能访问实例成员。
  • 静态类
    不能实例化,只能包含静态成员。
    静态类不能被继承,但是静态方法、属性都可以被继承。

  • 利:单独空间存储,所有对象共享,可直接被类名调用。
    弊:静态方法中只能访问静态成员,共享数据被多个对象访问会出现并发。

  • 适用场合:
    1. 所有对象需要共享的数据。
    2. 在没有对象前就要访问成员。
    3. 工具类适合做静态类(常用,不需要过多数据)。

struct
与类语法相似,都可以包含数据成员和方法成员。但结构属于值类型,类属于引用类型。
适用表示点、颜色等轻量级对象。如创建存储1000个点的数组,如果使用类,将为每个对象分配更多内存,使用结构可以节约资源。
除非字段被声明为 const 或 static,否则无法初始化。
结构不能继承,但可以实现接口。
结构总会包含无参数构造函数。
构造函数中必须初始化所有字段。
结构不能包含显式的无参数构造函数

集合
可对集合中的元素进行增删改查操作,作用都是原集合,而不会产生新的集合。

  • ArrayList
    底层就是一个可动态扩展的数组;
    提供了用于在集合中添加、删除或查找项的方法;
    ArrayList 集合不支持泛型(即:可放任意类型的数据);
    使用 ArrayList 集合之前,应先导入命名命名空间:using System.Collections ;
  • List
    类似于ArrayList集合,同样也提供了很多用于在集合中添加、删除或查找项的方法;提供了比ArrayList更多操作集合的方法
    List 集合支持泛型;
    List 集合默认的命名命名空间:using System.Collections.Generic;
  • Dictionary

内存分配

  • 类型分配
    值类型:存储数据本身。声明在栈中,数据存储在栈中。
    引用类型:存储数据的引用(内存地址) 声明在栈中,数据存储在堆中,栈中存储该数据的引用。
  • 内存分配
    程序运行时,CLR将申请的内存空间从逻辑上进行划分。
    • 栈区:
      — 空间小(1MB),读取速度快。
      — 用于存储正在执行的方法,分配的空间叫做栈帧。栈帧中存储方法的参数以及变量等数据。方法执行完毕后,对应的栈帧将被清除。
    • 堆区:
      — 空间大,读取速度慢。
      — 用于存储引用类型的数据。
  • GC(Garbage Collection)是CLR中一种针对托管堆自动回收释放内存的服务。
    GC线程从栈中的引用开始跟踪,从而判定哪些内存是正在使用的,若GC无法跟踪到某一块堆内存,那么就认为这块内存不再使用了,即为可回收的。

    使用比较运算符比较值类型时,对比的是存储的数值。
    比较引用类型时,对比的是引用的地址而不是数据。

×

喜欢就点赞,疼爱就打赏