一、C#语法基础
1. C#语言及其特点
- C#是微软公司发布的一种面向对象、运行于.NET Framework和.NET Core(完全开源,跨平台)之上的最高级程序设计语言。
- C#是一种安全的、稳定的、简单的、优雅的,由C和C++衍生出来的面向对象的程序语言。它在继承C和C++强大功能的同时去掉了一些他们的复杂特性。
- C#是面向对象的编程语言。
2. C#语法基础
2.1 cs文件结构
具体看一下各个部分:
- 程序第一行using System;-using关键字用于在程序中包含System命名空间。一个程序一般有多个using语句。
- 下一行是namespace声明。一个namespace是一系列的类。WebApplication1命名空间包含了类Program。
- 下一行是class声明。类Program包含了程序使用的数据和方法声明。类一般包含多个方法。方法定义了类的行为。在这里,Program类是有一个Main方法。
- 下一行定义了Main方法,是所有C#程序的入口点。Main方法说明当执行时类将做什么动作。
- Main方法通过方法体中的语句指定它的行为。
2.2 C#基本语法
以下几点值得注意:
- 一个cs文件的结构大约是由以上几个部分组成,但是根据不同的需求和作用,会有不同的内容。
- C#是大小写敏感的。
- 所有的语句和表达式必须以分号(;)结尾。
- 程序的执行从Main方法开始。
- 与Java不同的是,文件名可以不同于类的名称。
C#是一种面向对象的编程语言。在面向对象的程序设计方法中,程序由各种对象组成。相同种类的对象通常具有相同的类型。
2.3 关键字
关键字,是对编译器有特殊意义的预定义保留标识符,他们不能在程序中作标识符。
2.3.1 using关键字
在任何C#程序中的第一条语句都是:
using System;
using关键字用于在程序中包含命名空间。一个程序可以包含多个using语句。
2.3.2 class关键字
class关键字用于声明一个类。
2.3.3 C#注释方式
/*这个程序演示
C#语言的多行
注释语法*/
单行注释是用'//'符号表示。例如:
//这是C#语言单行注释方法
文档注释用'///'符号表示(用在方法和类上)。例如:
///<summary>
///这是主程序入口
///</summary>
///<param name="args">需要传入的参数</param>
public static void Main(string[] args)
{
}
注释的作用:
- 解释:说明代码作用
- 注销:将暂时不需要的代码注销
铭记:
- 不写注释是流氓
- 名字瞎起是扯淡
- 相比注销,注释意义更大
- 要做到别人一眼能看懂
2.3.4 变量
变量是一个供程序存储数据的盒子。在C#中,每个变量都有一个特定的类型,不同类型的变量其内存大小也不尽相同。
C#中提供的基本类型大致可以分为以下几类:
类型 | 举例 |
---|---|
整数类型 | byte、short、int、long(L) |
浮点型 | float(f)、double(d) |
十进制类型 | decimal(m) |
布尔类型 | bool |
字符类型 | string、char |
空类型 | null |
浮点型之间的转换只有float转换成double,decimal范围比float小,但精度比float高。
数字和布尔类型不可以直接赋为null类型。
二、C#语法进阶
1. 表达式
- 表达式由操作数(operand)和运算符(operator)构成。运算符的示例包括+、-、*、/和new。操作数的示例包括文本、字段、局部变量和表达式。
- 当表达式包含多个运算符时,运算符的优先级(precedence)控制各运算符的计算顺序。例如,表达式x+y*z按x+(y*z)计算,因为*运算符的优先级高于+运算符。
- (了解)大多数运算符都可以重载(overload)。运算符重载允许指定用户定义的运算符实现来执行运算,这些运算的操作数中至少有一个,甚至所有操作数都属于用户定义的类类型或结构类型。
- 下表总结了C#简单常用的运算符,并按优先级从高到低的顺序列出各运算符类别。同一类别中的运算符优先级相同。
类别 | 表达式 | 说明 |
---|---|---|
基本 | x.m | 成员访问 |
x(...) | 方法和委托调用 | |
x[...] | 数组和索引器访问 | |
new T(...) | 对象和委托创建 | |
new T(...){...} | 使用初始值设定项创建对象 | |
new{...} | 匿名对象初始值设定项 | |
new T[...] | 数组创建 | |
一元 | +x | 恒等 |
-x | 求相反数 | |
!x | 逻辑求反 | |
~x | 按位求反 | |
++x | 前增量 | |
--x | 前减量 | |
x++ | 后增量 | |
x-- | 后减量 | |
(T)x | 将x显示转换为类型T | |
二元 | x*y | 乘法 |
x/y | 除法 | |
x%y | 求余 | |
x+y | 加法、字符串串联 | |
x-y | 减法 | |
x<<y | 位左移 | |
x>>y | 位右移 | |
x<y | 小于 | |
x>y | 大于 | |
x<=y | 小于等于 | |
x>=y | 大于等于 | |
x is T | 如果x为T,则返回true,否则返回false | |
x as T | 返回转换为类型T的x,如果x不是T则返回null | |
x==y | 等于 | |
x!=y | 不等于 | |
x&y | 整型按位AND,布尔逻辑AND | |
x|y | 按位或 | |
x&&y | x和y都为true时,才为true(仅当x为true,才对y求值) | |
x||y | x或y为true时,就为true(仅当x为false,才对y求值) | |
x??y | 如果x为null,则计算结果为y,否则计算结果为x | |
三元 | x?y:z | 如果x为true,则对y求值;如果x为false,则对z求值 |
赋值或匿名函数 | x=y | 赋值 |
x=x+y | 复合赋值 | |
(T x)=>y | 匿名函数(lambda表达式) |
2. 分支语句
if语句
if(i>1){}
if-else
if(i>1)
{}
else
{}
if(i>=10)
{}
else if(i>0&&i<10)
{}
else
{}
switch语句
switch(i)
{
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
default:
...
break;
}
3. 循环语句
for循环
for(int i=0;i<10;i++)
{}
while循环
while(i<10)
{}
do-while循环
do
{}while(i<10);
4. 数组
- 数组是一组相同类型的数据。
- 数组中的数据需要通过数字索引来访问。
4.1 数组的声明
- 数组的声明需要使用new关键字。
- 在声明数组时,可以使用{}来初始化数组中的元素。
- 如果在数组声明之初没有使用大括号来初始化数组中的元素,则需要指定数组的大小。
- 在声明初始化有元素的数组时,也可以指定数组大小。
//声明没有元素的数组
int[] a = new int[6];
//声明初始化有元素的数组
int[] b = new int[] { 1, 2, 3, 4, 5, 6 };
//在声明初始化有元素的数组时,也可以指定数组大小
string[] c = new string[5] { "H","e","l","l","o" };
//简便写法
string[] c = { "H","e","l","l","o" };
4.2 通过索引获取数组中的元素
- 给数组指定长度时,数组准备存放多少元素,长度就设置为多少。
- 用索引获取数组内的元素时,索引从0开始获取。
- 所以数组中最大的索引数字,比指定数组长度小1。
//声明初始化有元素的数组
int[] arr = new int[6];
//获取数组中第一个元素
int i1 = arr[0];
//给数组内的元素赋值
arr[0] = 1;
扩展:
- (int)表示使用显示强制转换,是一种类型转换,C#默认整型是int32,因此使用此方法转成int32位,不遵循四舍五入,只截取整数部分;
- (int)5.21 //输出5
- Int.Parse():只支持将string类型转成int,parse就是把String类型转换成int,char,double...等,也就是*.Parse(string)括号中的一定要是string类型。
String st="5.21";
double n=5.21;
Int.Parse(st);
Int.Parse(n); //报错
Convert.ToInt32(double value),不完全遵循四舍五入,如果value为两个整数中间的数字,则返回二者中的偶数,对比下面的例子:
Convert.ToInt32(4.3); //四舍五入为4
Convert.ToInt32(4.5); //四舍五入为4
Convert.ToInt32(4.53); //四舍五入为5
Convert.ToInt32(5.4); //四舍五入为5
Convert.ToInt32(5.5); //四舍五入为6
Convert.ToInt32(5.53); //四舍五入为6
注意:Convert.ToInt32()和Int.Parse()对于空值(null)的处理不同,Convert.ToInt32(null)会返回0而不会产生任何异常,但Int.Parse(null)则会产生异常。
string a = "zhangsan";
string b = "lisi";
string c = "wangwu";
string[] sum = new string[3] { a, b, c };
int n = sum.Length; //arr.Length表示出数组元素个数
for (int i = 0; i < n; i++)
{
if (sum[i] == "wangwu")
{
MessageBox.Show("找到了" + sum[i]);
break;
}
}
5. 方法初识
- 函数好比是对象的动作行为,在C#中叫方法。
- 在定义方法要想好方法所承担的作用,职责(作用)约单一越好。
5.1 方法的命名规范
方法命名使用Pascal 规则: 每个单词开头的字母大写(如 TestCounter)。
变量命名使用Camel 规则: 除了第一个单词外的其他单词的开头字母大写(如 testCounter)。
5.2 方法的参数设置&传参行为
- 参数可认为是外部需要方法帮忙处理的数据。
- 外部通过传递参数的形式,将需要处理的数据交给方法处理。
5.3 方法返回值的设置
方法返回值可以认为是外部调用某种行为后得到的一种反馈。
/// <summary>
/// 加法方法
/// </summary>
/// <param name="x">数字1</param>
/// <param name="y">数字2</param>
/// <returns>返回的和</returns>
public int Add(int x, int y) //public表示方法的调用权限是公开的,int表示方法的返回值是int类型
{
return x + y;
}
5.4 参数修饰符
5.4.1 修饰符种类:
- 无修饰符:如果一个参数没有用参数修饰符标记,则认为它将按值进行传递,这将意味着被调用的方法受到原始数据的一份副本。
- out:输出参数由被调用的方法赋值,因此按引用传递,如果被调用的方法没有给输出参数赋值,就会出现编译错误(类似C中的指针形参变量)。out最大的用途就是调用者只使用一次方法就能获得的多个返回值。(在C#7.0中要实现一次方法的调用就能获得多个返回值,建议使用元组。)
- ref:调用者赋初值,并且可以由被调用的方法可选的重新赋值(数据是按引用传递的,类似C中的指针形参变量)。如果被调用的方法未能给ref参数赋值,也不会有编译错误。
- params:这个参数修饰符允许将一组可变的数量的参数作为单独的逻辑参数进行传递,方法只能有一个params修饰符,而且必须是方法的最后一个参数。
out和ref的区别:
- out修饰的参数必须在方法内修改,而ref可以修改也可以不修改;
- out在传入参数的时候,参数是局部变量的话,可以不用赋值,因为out一定会对其进行赋值;
- 而ref修饰的参数,在实参必须有初始值才能调用。因为ref修饰的不一定会给他赋值。
三、C#面向对象基本概念
1. 面向对象基本概念
- 之前所接触到的编程方式叫做面向过程
- 面向过程和面向对象是两种不同的编程方式
- 对比面向过程的特点,可以更好的了解什么是面向对象
1.1 过程和函数(科普)
- 过程是早期的一个编程概念
- 过程类似于函数,只能执行,但是没有返回值
- 函数不仅能执行,还可以返回结果
1.2 面向过程和面向对象基本概念
1)面向过程——怎么做?
- 把完成某一个需求的所有步骤从头到尾逐步实现
- 根据开发要求,将某些功能独立的代码封装成一个又一个函数
- 最后完成的代码,就是顺序的调用不同的函数
特点
- 注重步骤与过程,不注重职责分工
- 如果需求复杂,代码会变得很复杂
- 复杂项目没有固定的套路,难度很大
2)面向对象——谁来做?
相比较函数,面向对象是更大的封装,根据职责,在一个对象中封装多个方法
- 在完成某一个需求前,首先确定职责,要做的事情(方法)
- 根据职责,确定不同的对象,在对象内部封装不同的方法(多个)
- 最后完成代码,就是顺序的,让不同的对象调用不同的方法
特点
- 注重对象和职责,不同的对象承担不同的职责
- 更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供固定套路
- 需要在面向过程基础上,再学习一些面向对象的语法
2. 类和对象的概念
2.1 类
类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
- 特征被称为属性
- 行为被称为方法
类就相当于制汽车的图纸,是一个模板,是负责创建对象的
2.2 对象
- 对象是由类创造出来的一个具体存在,可以直接使用
- 有哪一个类创造出来的对象,就拥有在哪一个类中定义的属性和方法
- 对象就相当于是用图纸制造的汽车
2.3 类和对象的关系
- 类是模板,对象是根据类这个模板创建出来的,应该先有类,再有对象
- 类只有一个,而对象可以有很多个,不同的对象之间属性的具体内容可能各不相同
- 类中定义了什么属性和方法,对象中就有什么属性和方法,不可能多,也不可能少
3. 类的设计
在使用面向对象开发前,应该首先分析需求,确定一下程序中需要包含哪些类
在程序开发中要设计一个类,通常需要满足以下3个要素:
- 类名:这类事物的名称,满足Pascal 规则
- 属性:这类事物具有什么样的特征
- 方法:这类事物具有什么样的行为
3.1 类名的确定
名词提炼法:分析整个业务流程出现的名词,通常就是找到的类。
3.2 属性和方法的确定
- 对对象的特征,描述通常可以定义成属性。
- 对象具有的行为通常可以定义为方法。注:方法,一般是动作即动词。
4. 类和对象的使用
4.1 声明类
- 声明一个类需要使用 class 关键字
- 类的属性及方法写在大括号中
4.2 声明属性
- 属性在 C# 中较为独特,它既不同于方法,也不同于字段。
- 属性使用Pascal规则命名。
- 属性最常用的书写方法:public int Age{get;set;}
- 如果属性中具有 get 关键字,说明可以获取该属性的值
- 如果属性中具有 set 关键字,说明可以向该属性设置
4.3 声明方法
同函数声明
4.4 实例化
- 类使用关键字 new 实例化对象
- 一个类可以实例化多个对象
- 对象可以使用类定义的属性和方法
4.5 访问修饰符
- public:共有的 所有的类都可以访问
- private:私有的 当前类内部可访问
- protected:受保护的 当前类以及继承它的子类可访问
- internal:内部的 只限于本项目内访问,其他的不能访问
- protected internal:内部保护访问 只能是本项目内部或子类访问 其他类不能访问
访问级别约束:
- 父类子类访问修饰符要保持一致
- 方法的访问修饰符要和方法参数的访问修饰符保持一致
注意:类的访问级别默认internal,要加上public才能让外部访问。
静态方法、属性
- 静态方法和属性通过static关键字修饰
- 静态方法和属性通过类型直接获取,非静态则必须通过实例化的对象获取
- 静态方法只能使用静态属性
静态类
- 静态类通过static关键字修饰
- 一般情况下类型不需要使用静态修饰,只有当类型中存在扩展方法时需要使用静态类