C#语言基础篇

一、类型转换

   在 C# 中,变量分为以下几种类型:

  • 值类型(Value types)
  • 引用类型(Reference types)
  • 指针类型(Pointer types)

      1.值类型变量可以直接分配给一个值。它们是从类 System.ValueType 中派生的。值类型直接包含数据。比如 int、char、float,它们分别存储数字、字符、浮点数。当您声明一个 int 类型时,系统分配内存来存储值。

      2.引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用,指的是一个内存位置。内置的 引用类型有:objectdynamicstring

       1> 对象(Object)类型 是 C# 通用类型系统(Common Type System - CTS)中所有数据类型的终极基类。Object 是 System.Object 类的别名。所以对象(Object)类型可以被分配任何其他类型(值类型、引用类型、预定义类型或用户自定义类型)的值。但是,在分配值之前,需要先进行类型转换。当一个值类型转换为对象类型时,则被称为 装箱;另一方面,当一个对象类型转换为值类型时,则被称为 拆箱。(这个在前面的文章有提到过)

       2> 可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。eg:dynamic a = 100;

       3> 字符串(String)类型 允许您给变量分配任何字符串值。字符串(String)类型是 System.String 类的别名。它是从对象(Object)类型派生的。字符串(String)类型的值可以通过两种形式进行分配:引号和 @引号。

        C# string 字符串的前面可以加 @(称作"逐字字符串")将转义字符(\)当作普通字符对待,比如:

        string str = @"C:\Windows";      等价于    string str = "C:\\Windows";

       String和string的区别:

       1> string 是 C# 中的类,String 是 .net Framework 的类;(C# string 映射为 .net Framework 的String 如果用 string, 编译器会把它编译成 String,所以如果直接用 String 就可以让编译器少做一点点工作。)

        2> string 是关键字,String 不是,也就是说 string 不能作为类、结构、枚举、字段、变量、方法、属性的名称,而 String 可以。String 是 CLR 的类型名称,而 string 是 C# 中的关键字。

         3> String 只有在前面有 using System 的时候并且当前命名空间中没有名为 String 的类型(class、struct、delegate、enum)的时候才代表 System.String。

        4>string 在编译时候 C# 编译器会默认将其转换为 String,在这里会多增加几行转换的代码。很多时候都是建议使用 CLR 的类型而不要使用 C# 的类型。

        3.指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。eg:  int* iptr;

        注:变量的隐式类型转换zhin只能从低精度到高精度,所以,当一个精度高的数据类型与一个精度低的数据类型进行运算时,定义运算结果的变量类型必须与精度最高的变量类型相同。这是为了防止在运算过程中造成数据丢失。否则会出现类似的报错:无法将类型‘double’隐式转换为‘int’。

  1. Convert.ToInt32() 与 int.Parse() 的区别:

         1>Convert.ToInt32(a),int.Parse(a),但是如果a这个参数不存在,那么前者将返回0,而用后一种办法的话没有a这个参数会会抛出异常,我们可以捕获异常然后再做相应的处理,比如提示用户缺少参数,而不是把参数值当做0来处理;

         2>对数据的四舍五入有区别:Convert.ToInt32(double value); 如果 value 为两个整数中间的数字,则返回二者中的偶数;即 3.5转换为4,4.5 转换为 4,而 5.5 转换为 6。 不过4.6可以转换为5,4.4转换为4;int.Parse(4.5),结果是4,没有四舍五入。

         3>int.Parse 是转换 String为int;Convert.ToInt32是转换继承自Object的对象为int的(可以有很多其它类型的数据)。

         const和readonly区别:

         const,在编译时就确定了值,必须在声明时就进行初始化且之后不能进行更改,可在类和方法中定义。readonly,在运行时确定值,只能在声明时或构造函数中初始化,只能在类中定义。

二、封装

  • public:所有对象都可以访问;
  • private:对象本身在对象内部可以访问;
  • protected:只有该类对象及其子类对象可以访问
  • internal:同一个程序集的对象可以访问;
  • protected internal:访问限于当前程序集或派生自包含类的类型。

      参数传递:

       C# 中,有三种向方法传递参数的方式:

值参数 这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。
引用参数 这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值。形参和调用时的实参都需要加ref修饰。
输出参数 这种方式可以返回多个值。形参和调用时的实参都需要加out修饰。

out型数据在方法中必须要赋值,否则编译器会报错。

三、结构体

  • 结构可带有方法、字段、索引、属性、运算符方法和事件。
  • 结构可定义构造函数,但不能定义析构函数。但是,您不能为结构定义默认的构造函数。默认的构造函数是自动定义的,且不能被改变。
  • 与类不同,结构不能继承其他的结构或类。
  • 结构不能作为其他结构或类的基础结构。
  • 结构可实现一个或多个接口。
  • 结构成员不能指定为 abstract、virtual 或 protected。
  • 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构可以不使用 New 操作符即可被实例化。
  • 如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。
  • 类是引用类型,结构是值类型。
  • 结构体中声明的字段无法赋予初值,类可以。
  • 结构体中的构造函数必须对所有字段赋予初值,类可以不。
  • 类的对象是存储在堆空间中,结构存储在栈中。堆空间大,但访问速度较慢,栈空间小,访问速度相对更快。故而,当我们描述一个轻量级对象的时候,结构可提高效率,成本更低。当然,这也得从需求出发,假如我们在传值的时候希望传递的是对象的引用地址而不是对象的拷贝,就应该使用类了。当堆栈的空间很有限,且有大量的逻辑对象时,创建类要比创建结构好一些;对于点、矩形和颜色这样的轻量对象,假如要声明一个含有许多个颜色对象的数组,则CLR需要为每个对象分配内存,在这种情况下,使用结构的成本较低;在表现抽象和多级别的对象层次时,类是最好的选择,因为结构不支持继承。

四、静态

       可以使用 static 关键字把类成员定义为静态的。当我们声明一个类成员为静态时,意味着无论有多少个类的对象被创建,只会有一个该静态成员的副本。关键字 static 意味着类中只有一个该成员的实例。静态变量用于定义常量,因为它们的值可以通过直接调用类而不需要创建类的实例来获取。静态变量可在成员函数或类的定义外部进行初始化。你也可以在类的定义内部初始化静态变量。

五、继承

       C#不支持多重继承,但是可以通过接口实现。

       override是重写,即将基类的方法在派生类里直接抹去重新写,故而调用的方法就是子类方法;而new只是将基类的方法在派生类里隐藏起来,故而调用的仍旧是基类方法。

六、多态

        "一个接口,多个功能"。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。

        静态多态性: C# 提供了两种技术来实现,分别为:函数重载;运算符重载。

        动态多态性:C# 通过抽象类和虚方法实现。

        用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。派生类具有更专业的功能。

        抽象类的一些规则:

  • 您不能创建一个抽象类的实例。
  • 您不能在一个抽象类外部声明一个抽象方法。
  • 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。

       virtual和abstract的区别:

  1. virtual修饰的方法必须有实现(哪怕是仅仅添加一对大括号),而abstract修饰的方法一定不能实现。
  2. virtual可以被子类重写,而abstract必须被子类重写。
  3. 如果类成员被abstract修饰,则该类前必须添加abstract,因为只有抽象类才可以有抽象方法。
  4. 无法创建abstract类的实例,只能被继承无法实例化。

七、接口

       接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分。接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。

      1.通过接口可以实现多重继承,C# 接口的成员不能有 public、protected、internal、private 等修饰符。原因很简单,接口里面的方法都需要由外面接口实现去实现方法体,那么其修饰符必然是 public。

      2.C# 接口中的成员默认是 public 的。当一个接口实现一个接口,这2个接口中有相同的方法时,可用 new 关键字隐藏父接口中的方法。

      3.接口一旦被实现,实现类必须实现接口中的所有成员,除非实现类本身是抽象类。

       接口和抽象类的区别:

       1.接口用于规范,抽象类用于共性。抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。

       2.接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。

       3.抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。

        4.在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写。

        5.接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员。

持续更新中。。。后续有需要注意的会添加。

参考:http://www.runoob.com/csharp/csharp-polymorphism.html

这个系列的C#教程不错,推荐大家看看,认真看完你的C#语言会上一个层次。

猜你喜欢

转载自blog.csdn.net/jfy307596479/article/details/84965408