C#基本语法
C#基本语法
一、C#概念
- 面向对象
- 运行于.Net Framework、.Net Core和.Net之上的高级程序语言
- 派生于C和C++
- 功能:属性、事件、委托、泛型、多线程、linq、Lambda、特性等
二、.Net与C#的关系
- .Net是平台,C#是.Net平台之上的主流语言
三、项目文件
-
在App.config中配置connectStrings,从而配置数据库连接字符串
<connectStrings> <add name = "" connectString = "" providerName = "System.Data.SqlClient"/> </connectStrings> -
有时候会把数据库连接字符串配置到appSettings里面,value里面装连接字符串
<appSettings> <add key = "" value = ""/> </appsettings>
VS项目结构
- vs结构组成:菜单、工具栏
- 解决方案资源管理器:一个或多个项目容器
- 属性面板:在属性面板中调整相关参数
- 工具箱:提供控件或组件面板,可以从中直接拖动到界面上
- 错误列表:罗列代码中的错误,可以定位与找到错误、
- 输出:项目输出信息
四、C#类文件结构
-
包含行号、关键字、类、命名空间、方法、方法体、Main
-
关键字:
using namespace public class static void -
类:一个类包含一个或多个方法、属性、变量等
-
方法:定义了类的行为
-
方法体:方法的具体代码
-
Main:程序的入口点,如控制台、Winform应用程序
-
C#类文件结构示例:
using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; //引用命名空间 namespace WebApplication //项目的命名空间,大多数时候也是项目本身的名称 { public class program //类名称 { public static void Main(string[] args) //方法或者叫函数 { //大括号内部为方法体,用于写具体代码 } } }
五、C#的基本语法
关键字
-
有特殊含义的预定义保留标识符,代码中以蓝色标识的单词
-
如class、private、namespace、using……
-
类名以绿色表示
- 类class的默认标识符是internal,同一个项目的内部可以访问,另外一个项目就不可以访问,类前面的访问修饰符不能用private
using System; namespace WinFirst { //默认是internal class StudentInfo { } }
注释方式
- 对代码进行解释
- 不需要的代码可以注释掉
- 行注释,以//注释
- 块注释,以/* */注释
- 文档注释,以///注释,并加上文字说明
// 单行注释
/*
多行注释
多行注释
多行注释
*/
/// <summary>
/// 文档注释
/// </summary>
数据类型
-
变量:存储数据的容器,在C#中,每个变量都有一个特定类型,不同类型占有的内存大小不尽相同
-
C#中变量的数据类型分为:值类型、引用类型、指针类型。
值类型
值类型的定义
整型
- byte的范围:0~255
- short的范围:-32768~32767
- int的范围:-2147483648~2147483647
- long的范围:-9×1018~9×1018
浮点型
- float的范围:-3.4×1038~3.4×1038,单精度,有精度损耗
- double的范围:+/-)5.0×10-324~(+/-)1.7×10308,双精度
十进制
- decimal(精确):无损耗,可以表示小数
布尔类型
- true
- false
- bool
字符类型
- string必须加“”
- char只能包含一个字符,如'a'
可空类型
- Nullable<T>,基础值类型正常范围内的值,再加上一个null值
- 可空类型是一个泛型
- T就是一个基础类型
- 基础类型范围的值再加上一个null
枚举
- enum,一组命名的整型常量
- 用enum关键字来声明
- 值类型
结构体
- struct
- 值类型数据结构,感觉和使用类差不多
- 单一变量,可以存储各种数据类型的相关数据
- 可以把多个数据存在一个变量里
- 里面定义的方法访问修饰符必须是public
结构体的特点
-
用struct关键字定义
-
结构可带有方法、字段、索引、属性、方法和事件
-
结构可以定义构造函数,不能定义析构函数
-
不能为结构体定义无参构造函数,无参构造函数是自动定义的,且不能被改变
-
与类不同,结构不能继承其他的结构或类
-
结构不能作为其他结构或类的基础结构
-
结构可实现一个或多个接口
-
结构成员不能指定为abstract、virtual或protected
-
结构可以不使用new操作符被实例化
using System;
namespace WinFirst
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
int a;
a = 23; //=号读作“赋值”
int b = 2 + a;//在这里+号起到一个加的作用
float c = 2.3F;//浮点型命名时默认必须加F
double d = 2.22;
bool bl = true;
string ss = "aaaa"+"bb";//在字符串中+号起到一个拼接的作用
int b1 = 1;
b1 += 1; //这个公式等价于b1 = b1 + 1,自加一。
string s = "";//分配内存,长度为0
string sss = null;//和上面那个式子不等价,不占用内存
//int aa = null;错
int? aaa = null;//Nullable<int>
Days day = Days.Monday;
User user;//实例化的一种方式,也可以写成User user = new User();
user.Id = 1;
user.Name = "John";
user.Say();
}
//用enum来定义
private enum Days
{
Monday,Tuesday,Wednesday
}
struct User
{
public int Id;
public string Name;
//不能定义无参构造函数
public User(int Id,string name)
{
Id = id;
Name = name;
}
//在struct中可以定义方法,但是访问修饰符必须是public
public void Say()
{
}
}
}
引用类型
- 不包含存储在变量中的实际数据
- 包含对变量的引用
- 它们存储的是一个内存位置
- 如果多个变量使用的是同一个引用,他们指向同一个位置
- 当其中一个变量改变,其他变量也会自动改变
- 内置的引用类型:object、dynamic和string
对象类型
-
object,基类
-
装箱:值类型转换为对象类型
-
拆箱:对象类型转换为值类型
-
存在对象类型中的变量的类型检查是在编译时发生的
using System;
namespace WinFirst
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
object o = a;//将值类型放到引用类型中,就是一个装箱的操作
int ee = (int)o;//强制转换,引用类型转换为值类型就经历了一个拆箱的操作
}
}
动态类型
- dynamic
- 任何类型的值都可以存储在动态类型中,这些变量的类型检查是在运行时发生的,编译的时候不会检查错误
- 类型不安全,只有在运行的时候才会发现错误
- 声明动态类型的语法:dynamic <variable_name> = value; dynamic name ="John"
using System;
namespace WinFirst
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
dynamic ddd = 233;//声明了值类型的ddd
MessageBox.Show(ddd);//MessageBox.Show方法执行的是string类型,这里无法检查出值类型的ddd,只有在运行的时候才会发现错误,这个就是类型不安全
}
}
字符串类型
- string
- 允许您给变量分配任何字符串值
- string类型的值可以通过两种形式进行分配:引号和@引号
- 如,string ss = "John" 或 ss = @ "John"
- @字符将字符串里面的转义字符(\)当作普通字符对待
- @字符串中可以任意换行
using System;
namespace WinFirst
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
string connStr = "server = .\\sqlexpress";
string connStr = @"server = .\sqlexpress";//上下两句意思相同
}
}
类型转换
- 把数据从一个类型转换为另一种类型
- 隐式转换:C#默认的以安全的方式转换,不会导致数据丢失
- 显示转换:强制转换,会造成数据丢失
- ToInt32、ToString、ToDecimal、ToDateTime
- int.Parse(string)、Convert.ToInt32(val)
using System;
namespace WinFirst
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender,EventArgs e)
{
string stuId = "23";
//int Id = (int)stuId;//error
int Id = int.Parse(stuId);//问题:如果字符串不是数值,就会报错
//类型转换 datatype.Parse(string) Convert.ToInt32(任意类型)
//Convert.ChangeType(val,type);
int Id0 = 0;
int.TryParse =(stuId,out id0);//不管是否成功,不会出异常
Convert.ToInt32(ss);
Convert.ToInt32(o);
}
变量
- 存储数据的名字,有特点类型,决定变量内存的大小和布局
- 定义语法:数据类型 变量名或变量列表,可以在定义时进行初始化,如,int a = 10;
- 同种类型可以一次定义多个
- 常量用const来定义,常量定义后无法再改变
int a = 0,b = 1,c = 2;
const int d = 5;//无法再改变
表达式和变量作用域
- 表达式是运算符和操作数的字符串
- 表达式可以由许多嵌套的子表达式构成,这就产生了求值顺序,运算符的优先级
- 表达式是由运算符连接常量、变量和函数的式子,每个表达式都有一个值和类型
运算符
-
算数运算符:+ - * / % ++ --
-
关系运算符:> < >= <= != ==
-
逻辑运算符:&& || !
-
赋值运算符:= += -= *= /= %=
-
三目运算符:?: 如a>0?1:2
int a = 1; string aa = a == 1?"add":"del";//等于1时增加,否则删除
作用域
- 变量可以访问的区域
null
- 不引用任何对象的空引用的文字值。引用变量的默认值。
- 一个变量赋值为null,是不会分配存储空间的
- null与“”的区别,""会分配存储空间,长度为0,string.Empty就是““(空字符串)
选择分支
if语句
-
if 只会执行符合条件的语句块,后面的就不会执行
int score = 66; int grade = 1; if(score >= 90 && score <= 100) { grade = 1; } else if(score >= 80 && score < 90) { grade = 2; } else if(score >= 70 && score < 80) { grade = 3; } else if(score >= 60 && score < 70) { grade = 4; } else if(score >= 50 && score < 60) { grade = 5; }
switch语句
- 满足某一条件,直接执行该条件的语句
int score = 66;
switch(score / 10)
{
case 10:
grade = 1;
break;
case 9:
grade = 2;
break;
case 8:
grade = 3;
break;
case 7:
grade = 4;
break;
default:
grade = 5;
break;
}
循环
while循环
while(布尔条件表达式)
{
循环语句;
}
for循环
for(表达式1;表达式2;表达式3)
{
循环语句;
}
for(int = i;i <=100)
{
total +=i;
i++;
}
冒泡排序
for(int i = 0;i<arr.Length;)
{
for(int j = 0;j<arr.Length-i-1;j++)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[1+i];
arr[j+1]=temp;
}
}
}
Console.WriteLine(string.Join(",",arr));
九九乘法表
for(int i = 1;i <= 9;i++)
{
string str ="";
for(int j = 1;j <= i;j++)
{
str +=$"{i}*{j}={i*j}";
if(j < 9)
str += " ";
}
Console.WriteLine(str);
}
foreach循环
- 访问集合或数组中的每一个元素,并针对每个元素执行循环代码
- foreach的效率比for的效率高
foreach(数组类型 元素 in 集合或数组)
{
代码块
}
do...while循环
- 即使条件不满足,至少会执行一次
do
{
循环语句;
}
while(布尔表达式);
嵌套循环
循环控制语句
break语句
- 终止循环
continue语句
- 跳出该次执行, 立即重新开始测试条件
- 跳出本次循环,继续下次循环
无限循环
-
条件永不为假,则循环变为无限循环
-
设置退出条件进行推出
int i = 0; while(true) { i += 1; if (i == 6) continue; if (i > 100) break; }
类
-
引用类型的代表
-
类是一种数据结构,可以包含数据成员(常量和域)、函数成员(方法、属性、事件、索引器、运算符、构造函数和析构函数)和嵌套类型等。
-
一系列在概念上有相同含义的对象
-
类使用关键字class来声明
-
类的访问修饰符默认是internal
-
构造函数默认为private,析构函数不能显示使用访问修饰符且默认为private,类的成员默认访问修饰符为private
- 析构函数是程序关闭时自动运行的,不能手动访问
访问修饰符
在名称空间中定义元素的时候,只能使用public和internal两种
成员的默认修饰符是private
namespace win
{
//默认是internal
class people
{
//默认是private
int id;
}
}
- public
- 公共的,访问完全不受限制
- protected
- 受保护的,仅在本类和本类的子类可以访问,可以跨程序集访问
- 不可以通过类的实例访问
- private
- 私有的,仅在本类中使用
- 子类不可以访问,类的实例也不可以访问
- 一般来修饰成员变量、方法、属性等等
- internal
- 内部的,仅本项目中可以访问
- 本项目表示同一个程序或同一个程序集中
组合修饰符
- protected internal
- 受保护的内部
- private protected
方法修饰符
- static
- 静态的
- 表示该方法是类的一部分,而不是实例的一部分
- 不可以通过对象的实例去访问该方法,而是通过类名去访问的
- 指定classname.method(parameters)来支持访问类,而无需创建类实例
- virtual
- 虚方法
- 该方法可以在子类中重写覆盖父类中的方法
- 不能与static或private访问该修饰符一同使用
- override
- 重写
- 该方法覆盖了父类中的同名方法,父类中被覆盖的方法必须是virtual(虚方法)
- 定义子类特有的行为,覆盖父类中的行为
- new
- 重写“隐藏”父类中同名的非虚方法
- 它会取代原方法,而不是覆盖
- sealed
- 禁止派生此方法
- 必须与override修饰符一起使用
- abstract
- 抽象的,只能定义方法的参数结构,不包含具体实现细节,细节必须由子类完成
- 只能用做abstract类的成员
构造函数和析构函数
构造函数
- 是在创建给定类型的对象时执行的类方法
- 具有与类相同的名称
- 通常用于初始化新对象的数据成员
- 构造函数分为无参构造函数、带参数的构造函数
析构函数
- 析构函数的名称是在类的名称前面加上“~”作为前缀,没有返回值,不带任何参数
- 一个类只能有一个析构函数且无法调用,它是被自动调用的
静态成员
- static 关键字把类成员定义为静态的
- 无论有多少个类的对象被创建,只会有一个该静态成员的副本
- 静态变量可在成员函数或类的定义外部进行初始化
- 可以把一个成员函数声明为 static,这样的函数只能访问静态变量
- 静态函数在对象被创建之前就已经存在
方法
定义
把一些相关的语句组织在一起,用来执行一个任务的语句块
使用方法
定义方法、调用方法
语法
访问修饰符 修饰符 返回值类型 方法名(参数列表)
{
语句块;
}
访问修饰符:public、private、protected,对于另一个类的可见性,默认是private
修饰符: virtual (虚拟的) 、abstract(抽象的) 、override(重写的) 、static(静态的) 、 sealed(密封的)
返回值类型:用于指定返回结果的数据类型,返回值可以是任意的数据类型,如果指定了返回值类型,必须使用return关键字返回一个与之类型匹配的值,没有返回值,使用void
方法名:对方法所实现功能的描述。方法名的命名是以Pascal命名法为规范的,首字母大写
参数列表:在方法中允许有0到多个参数,如果没有指定参数也要保留参数列表的小括号
抽象类
定义
- 使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现
- 当一个派生类继承自该抽象类时,实现即完成
- 实现多态的一种方法
- 抽象类包含抽象方法,抽象方法可被派生类实现
抽象类的规则
- 抽象类不能直接实例化
- 抽象方法只能定义在抽象类中
- 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。
何为抽象
- ”身份证“和身份证号的关系,”姓名“和”张三“直接的关系,”姓名“就是抽象的,”张三“就是实现细节
虚方法
-
当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法
-
虚方法是使用关键字virtual声明的
-
虚方法可以在不同的继承类中有不同的实现
-
对虚方法的调用是在运行时发生的
-
如果一个方法不是虚方法,它在子类里面有覆盖,调用的还是父类里面的方法,如果是虚方法,它在子类里面覆盖,调用的是子类里面的方法
继承
- 继承允许我们根据一个类来定义另一个类,使得创建和维护应用程序变得更容易。同时也有利于重用代码和节省开发时间
- 当创建一个类时,程序员不需要完全重新编写新的数据成员和成员函数,只需要设计一个新的类,继承已有的类的成员即可
- 已有的类被称为的基类或父类,新的类被称为派生类或子类
- 子类继承父类的数据和函数
C#多重继承
- C# 不支持多重继承。但是,可以使用接口来实现多重继承
- 一个类不继承多个类,但是可以继承多个接口
- 多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。与单一继承相对,单一继承指一个类别只可以继承自一个父类
接口
- 接口(interface)用来定义一种程序的协定
- 实现接口的类(或者结构)要与接口的定义严格一致
- 接口可以继承多个接口,类(或结构)可以实现多个接口
- 接口可以包含方法、属性、事件和索引器
- 接口本身不提供它所定义的成员的实现,接口只指定实现该接口的类或接口必须提供的成员
- 接口好比一种模版,这种模版定义了对象必须实现的方法,它自己本身不去实现这些方法,这些方法的具体实现交给它的实现类来完成,其目的就是让这些方法可以作为接口实例被引用。接口不能被实例化。
- C#中的接口是独立于类来定义的,接口和类都可以继承多个接口,而类可以继承一个基类,接口根本不能继承类。
接口语法
interface IMyInterface//接口名称
{
void Method ToImplement(); //方法定义,接口中只能包含方法的定义
}
- 类同时实现接口和继承类时,继承类必须放在接口前面
封装
定义
-
将数据或函数等集合在一个个的单元(类)中
-
被封装的对象通常被称为抽象数据类型
作用
- 封装的意义在于保护或者防止代码(数据)被我们无意中破坏
- 封装既可以封装成员变量,又可以封装成员方法
- 对象就是类的实例,类就是对对象的类型的抽象
多态
定义
- 多态是同一个行为具有多个不同表现形式或形态的能力。
- 多态意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"
- 在 C# 中,每个类型都是多态的,因为包括用户定义类型在内的所有类型都继承自 Object
实现方式
静态多态
- 函数重载
- 同一个范围内对相同的函数名有多个定义
- 函数的定义必须彼此不同,可以是参数列表中的参数类型不同,也可以是参数个数不同,即方法的签名不同
- 不能重载只有返回类型不同的函数声明
动态多态
- 可以通过抽象类、虚方法和接口实现多态

浙公网安备 33010602011771号