1.基本语法
using关键字:在C#程序中第一条语句为 using System
class关键字:常用于声明一个类
注释:用于解释代码,多行注释以 /* 开始,并以字符 */ 终止,单行注释是用 ‘//’ 符号表示
成员变量:变量是类的属性或数据成员,用于存储数据
成员函数:函数是一系列执行指定任务的语句,类的成员函数是在类内声明的
标识符:用来识别类、变量、函数或任何其它用户定义的项目,以下为类的命名的基本规则
关键字:关键字是 C# 编译器预定义的保留字。这些关键字不能用作标识符,如果想使用这些关键字作为标识符,可以在关键字前面加上 @ 字符作为前缀。在 C# 中,有些关键字在代码的上下文中有特殊的意义,如 get 和 set,这些被称为上下文关键字(contextual keywords)。下表列出了 C# 中的保留关键字(Reserved Keywords)和上下文关键字(Contextual Keywords)
2.数据类型
值类型(Value types):整型、浮点型、字符型、布尔型、枚举型
1.整型类型的分类、占用内存大小以及最大可表示范围
2. 浮点型(小数)是指小数类型,浮点型在 C# 语言中共有两种,一种称为单精度浮点型(float 4个字节),一种称为双精度浮点型(double 8个字节)。二者表示的精度范围不同。精度更高的浮点类型:decimal类型,它占16个字节,使用需要在数字的后面加上字符M或(m)来表示,例如 123.45M、123.45m。
decimal d=12.30M;
3.字符型只能存放一个字符,它固定占用两个字节,能存放一个汉字,字符型用 char 关键字表示,存放到 char 类型的字符需要使用单引号括起来,例如'a'、'中' 等。char c = 'A';
注意:字符型只能使用单引号。 双引号代表字符串类型。
4.布尔类型使用 bool 来声明,它只有两个值,即 true 和 false。
引用类型(Reference types):类(class、object、string)、接口(interface)、数组(array)、
委托(delegate) 、字符串
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。
在使用多个变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由一个变量改变的,其他变量会自动反映这种值得变化。内置的引用类型有: object、dynamic和string。
指针类型(仅用于非安全代码)
指针类型变量存储另一种类型的内存地址。C# 中的指针与 C 或 C++ 中的指针有相同的功能。
声明指针类型的语法:
type * identifier;
Eg:
char* cprt;
int* iptr;
3.数组
可以将同一类型的多个变量存储在一个数组数据结构中。通过指定数组的元素类型来声明数组。 如果希望数组存储任意类型的元素,可将其类型指定为 object。数组是一个引用类型。数组,是一种数据结构。引用类型
按维度分:一维数组 将一组值存放到一个数组中,并为其定义一个名称,通过数组中元素的位置来存取值。多维数组 多维数组中常见的是二维数组。二维数组中的子元素是一维数组。
数组的访问:用下标的方式访问数组元素; 数组元素的值可被同类型的值修改。
一维数组的声明:
//数组包含5个元素,每个元素的值默认为0 (类型)
int[] array = new int[5];
//数组包含6个元素,每个元素的值默认为""(字符串类型)
string[] stringArray = new string[6];
数组的初始化:
int[] array1 = new int[] { 1, 3, 5, 7, 9 };//数组长度为5,每个元素的值都不同
隐式类型化数组:
int[] array2 = { 1, 3, 5, 7, 9 };
声明数组变量,但必须使用 new 运算符向此变量分配新数组。
//a.声明数组变量
int[] array3;
//b.给这个变量赋值
array3 = new int[] { 1, 3, 5, 7, 9 };
//相当于数组的初始化:
【 int[] array3=new int[]{ 1, 3, 5, 7, 9 } 】
访问数组元素
Console.WriteLine(array3[0]);//输出 1
修改数组元素
array3[0]=2;
4.创建对象和对象的使用
(1)实例化方法,也就是new();
(2)Activator 创建实例;
(3)反射创建实例;
注意: 其中第一和第二效率高,第三由于是反射,效率略低。
5.构造函数
用于执行类的实例的初始化。每个类都有构造函数。C#中通过new关键字创建对象的过程其实就是通过new关键字调用类的构造函数的过程。创建对象时,必须调用构造函数,如果没有定义构造函数,系统会提供一个默认的构造函数。
创建构造函数的语法如下:
class 类名
{
<访问修饰符> 类名()
{
//构造函数主体
}
}
构造函数的定义规则:
(1)C# 语言的构造函数的名称必须与类名相同。
(2)构造函数没有返回值。它可以带参数,也可以不带参数。
(3)声明类对象时,系统自动调用构造函数。在构造函数中不要做对类的实例进行初始化以外的事情,也不能被显式地调用。
(4)构造函数可以重载,从而提供初始化类对象的不同方法;
(5)若在声明时未定义构造函数,系统会自动生成默认的构造函数,此时构造函数的函数体为空。
(6)静态构造函数,用static修饰,用于初始化静态变量,一个类只允许有一个构造函数,在类实例化时加载,这时修饰符public、private失去作用。
(7)构造函数可以使用public、protected、private修饰符。一般地,构造函数总是public 类型的。private 类型的构造函数表明类不能被实例化,通常用于只含有静态成员的类。
(8)引用父类构造时用():base()方法,引用自身重载的构造使用():this(int para)。
(8)一个构造函数的返回类型是这个类的一个实例,而一个普通方法的返回类型可以是任何类型。
注意:
下面的代码说明了构造函数的声明方式:
// 构造对象时将执行构造函数
using System;
public class Dog
public string name;
public Dog() // 声明构造函数
{
this.name = "未知";
Console.WriteLine("Dog():Dog类已被初始化。");
}
public static void Main()
{
Dog myDog = new Dog(); // 会调用构造函数
Console.WriteLine("myDog的名字为“{0}”。);
}
}
下面这种构造函数不接受任何参数,称为无参数构造函数。
class TestClass{
public TestClass(): base() {} // 由CLR提供
}
6、属性、匿名类、Var类型
属性是类(class)、结构(structure)和接口(interface)的命名(named)成员。类或结构中的成员变量或方法称为域(Field)。
属性不会确定确定存储位置。相反,它们具有可读写或计算它们值的访问器(accessors)
访问器(accessors):包含有助于获取(读取或计算)或设置(写入)属性的可执行语句;声明可包含一个get访问器、一个set访问器,或者同时包含二者。
匿名类
匿名类就是没有名字的类。匿名类不能被引用,只能再创建的时候用new语句来声明。
规则:1、匿名类型提供了一种方便的方法,可以用来将一组只读属性封装到单个的对象中,而且并不需要首先显示定义一个类型。
2、类型名由编译器生成,并且不能在源代码级使用。每个属性的类型由编译器推断。
3、可通过是用new运算符和对象初始值创建匿名类型。
4、匿名类型通常用在查询表达式的 Select 子句中,以便返回原序列中每个对象的属性子集(Linq 中使用的比较多)。
//匿名类型 var news = new {title="冰红茶",day="2019-4-10",author="康师傅"}; showInfo(news); // static void ShowInfo<T>(T news) { dynamic d = news; Console.WriteLine(d.title); Console.WriteLine(d.day); Console.WriteLine(d.author); }
var隐式类型
隐式类型var,声明变量是无需指定数据类型的,编译器会根据赋值判断其类型的一种机制,它的优势就在于,通过var这个隐式类型,可以提高开发人员的开发效率,很多时候可以不考虑对象的类型。
var 的使用规则;
1、var 类型会被编译器根据初始值的类型推断出具体的类型;
2、var 类型的局部变量必须赋予初始值;
3、无法将null赋值给隐式类型的局部变量;
4、var 类型变量的定义必须是在方法中或者在属性get、set 访问器中;
5、var 不能做方法的参数;
6、不能当作返回值类型;
7、语句中只能声明一次变量,声明后不能更改类型;
匿名方法的实例:
/*匿名方法的演化过程*/ MySumHandler m1 = new MySumHandler(Sum); m1(2,3); MySumHandler m2 = Sum; m2(3,4); //匿名方法,C#2.0 MySumHandler m3 = delegate(int i, int j){Console.WriteLine("{0}+{1}={2}",i,j,(i+j));}; m3(5,6); //lambda,表达式C#3.0 MySumHandler m4 = (i,j)=>{Console.WriteLine("{0}+{1}={2}",i,j,(i+j));};
7、继承
继承是指对C语言中现有类(基类、父类)上建立新类(派生类、子类)的处理过程。
继承的作用:
1、使程序的创建和维护变得很容易;
2、有利于代码的重用和节省时间;
3、编写时候可以更快的理解和应用
继承的特点:
1、继承了基类/父类的属性和方法,子类可以继承父类的可继承属性、函数;
2、继承时并非完全继承,只有可继承的类成员才可以被继承,主要使用访问修饰符进行设置;
3、继承实质上是对象与对象之间的关系;
4、C#继承只能实现单继承,每个类只能继承一个父类,一个父类可以拥有多个子类;
5、继承可以隔代继承,也就是子类下面还可以有子类;
6、不允许相互继承(循环继承);
7、C#不允许多重继承,但是可以实现多重接口继承;
基类和派生类:
基类/父类:也可以理解成生活中的父亲,自身所拥有的一些属性方法会被继承;
派生类/子类:也就是生活中的儿子,自己去继承了基类/父类的属性和方法,当然自身也会拥有自己的属性和方法。
C#中创建派生类的语法:
<访问修饰符> class <基类>
{
...
}
class <派生类> : <基类>
{
...
}
基类/父类:
class Animial
{
public string name;
public int age;
public string love;
public void Fisft()
{
Console.WriteLine("吃饭不是为了吃,关键是气氛搞起来!");
}
public void Second()
{
Console.WriteLine("经常被自己的聪明所秀到!");
}
}
派生类/子类:
class Dog:Animial
{
}
调用此类的属性和方法:
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
dog.name = "哈士奇";
dog.age = 02;
dog.love = "拆家,搞事情,瞪眼睛";
Console.WriteLine("我的名字叫{0},我今年{1}岁啦,我的爱好是{2}", dog.name, dog.age, dog.love);
Console.ReadLine();
dog.Fisft();
Console.ReadLine();
dog.Second();
Console.ReadLine();
}
}
C#多重继承
多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。与单一继承相对,单一继承指一个类别只可以继承自一个父类。
C#不支持多重继承。但可以使用接口来实现多重继承。
8.this和base关键字
this关键字:用于引用类的当前实例,也包括继承而来的方法,通常可以隐藏this。
功能主要包括:
(1)限定被相似的名称隐藏的成员
(2)将对象作为参数传递到其他方法
(3)声明索引器
this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成员,而且不管访问元素是任何访问级别。因为,this仅仅局限于对象内部,对象外部是无法看到的,这就是this的基本思想。
注意:静态成员不是对象的一部分,因此不能在静态方法中引用this。准确来说,this关键字不能在静态方法的方法体(即大括号之间的部分)中使用、但是可以在参数中使用(即C#的扩展方法)。
base关键字:用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数、实例方法和实例属性访问器中。
功能主要包括:
(1)调用基类上已被其他方法重写的方法。
(2)指定创建派生类实例时应调用的基类构造函数。
base常用于,在派生类对象初始化时和基类进行通信。
base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。
在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存在的情况下,base将指向直接继承的父类成员的方法;而没有重载存在的情况下,base可以指向任何上级父类的公有或者受保护方法。
注意:base关键字不能在静态方法中使用。
用法注意
1、base常用于,在派生类对象初始化时和基类进行通信。
2、base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。
3、this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成员,而且不管访问元素是任何访问级别。因为,this仅仅局限于对象内部,对象外部是无法看到的,这就是this的基本思想。另外,静态成员不是对象的一部分,因此不能在静态方法中引用this。
4、在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存在的情况下,base将指向直接继承的父类成员的方法;而没有重载存在的情况下,base可以指向任何上级父类的公有或者受保护方法。
C# 实例化的正确顺序
派生类静态字段被实例化。
派生类静态构造函数被调用。
派生类实例成员字段被实例化。
基类静态字段被实例化。
基类静态构造函数被调用。
基类实例成员字段被实例化。
基类构造函数被调用。
派生类构造函数被调用。
9、虚方法Virtual
当有一个定义在类中的函数需要再继承类中实现时,可以使用虚方法,虚方法是使用关键字virtual
声明的,虚方法可以再不同的继承类中有不同的实现,即为基类中定义的允许再派生类中重写的方法;
virtual的使用会有两种情况:
情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
声明形式:
访问修饰符 virtual 函数返回类型 函数名(参数表){函数体};
作用:
1.可在派生类中以override覆盖此方法
2.不覆盖也可由对象调用
3.无此标记的方法(也无其他标记),重写时需用new隐藏原方法
10、什么是接口
接口是指定一组函数成员而不实现成员的引用类型,其他类型-类和结构可以实现接口。一个类能同时实现多个接口,还能在实现接口的同时再继承其他类,并且接口之间也可以继承,所有继承都使用“:”来表示。
语法形式:
interface 接口名称
{
接口成员;
}
实现方式:a. 接口名称:以 I 开头,再加上其他的单词构成
b. 接口成员:与类中定义的成员类似。
注意:不允许使用 public、private、protected、internal 访问修饰符;不允许使用 static、virtual、abstract、sealed 修饰符;不能定义字段;定义的方法不能包含方法体。
接口的实现:类中实现一个接口时必须将接口中的所有成员都实现,否则该类必须声明为抽象类,并将接口中未实现的成员以抽象方式实现。
语法形式:
class 类名 : 接口名
{
//类中的成员以及实现接口中的成员
}
实现方式:
a. 隐式实现接口成员:将接口的所有成员以 public 访问修饰符修饰
b. 显式实现接口成员:所实现的成员名称前用接口名称作前缀且不能再使用修饰符修饰
11、索引器
索引器(Indexer)是C#引入的一个新型的类成员,它使得类的对象可以像数组那样引用。索引器非常类似于属性,但索引器可以有参数列表,且只能作用在实例对象上,而不能在类上直接作用。
语法:
element-type this [int index]
{
//get 访问器
get
{
//返回index指定的值
}
//set 访问器
set
{
//设置index指定的值
}
}
创建索引器时有几部分内容是必须的:
1、必须先创建索引器所需要的容器(我把它称为容器,暂时还没看到有对它的具体定义)
2、创建索引器需要使用this关键字
3、索引器中必须要包含get和set访问器,在C#7.0可以使用表达式主体(=>)简化
4、在使用表达式主体成员实现索引器时,必须额外提供容器的修改接口,因为通过表达式主体实现的索引器是不包含set关键字的
重载索引器索引器可被重载。
索引器声明的时候也可带有多个参数,且每个参数可以是不同的类型。没有必要让索引器必须是整型的。C#允许索引器可以是其他类型。
12、运算符
1、算数运算符
算数运算符就是简单的+. -. *. /;
唯一特别的是“+”,就是可以代表两个数字是相加也可以做为一个拼接。
2、关系运算符
关系运算符就是比较两个数字或者别的东西之间的大小相等否关系的。
关系运算符有相等(==),不相等(!=),大于(>),小于(<),大于等于(>=),小于等于(<=);
3、逻辑运算符
逻辑运算符主要包括与(&&)、或(||)、非(!)等,它主要用于多个布尔型表达式之间的运算。
4、位运算,通常是指将数值型的值从十进制转换成二进制后的运算,由于是对二进制数进行运算,所以使用位运算符对操作数进行运算的速度稍快。(&)、或(|)、 非(~)、左移(>>)、右移(<<)等;
5、赋值运算符
6.特殊运算符
特殊运算符包含自增运算符(++),自减运算符(--)和条件运算符(?:)。
其实特殊运算符中的自增运算符(++),自减运算符(--)已经是在赋值运算符中的了;
所以在我的心中特殊运算符只有一个就是条件运算符。
:条件运算符(?:):
条件运算符一般是一个 布尔表达式 ? 表达式 1: 表达式 2
布尔表达式 成立就执行第一个表达式反之执行第二个表达式。
7、运算符优先级
运算符优先级如下表所示: