C#详细学习教程
c#
学习网站文章更全:C#学习网站 点击跳转
如果文章信息错误或过时,请移步至我的博客:https://www.lincol29.cn
,内容更新仅在个人博客可见(请到我的博客获取第一手信息),欢迎关注!
如何去学习一门语言
每天学习做好笔记,思维导图。不是为了以后更好复习,而是为了能够更好的梳理以及记忆知识点。万丈高楼平地起,要想学习好,必须打好基础,切记心浮气躁
简介:.Net平台 .Netframework框架提供了运行环境和技术
.net可以干什么?
1.桌面应用程序 winform
2. Internet应用程序 ASP.NET 比如:携程、招商银行
3. 手机开发
4. Unity游戏开发或者虚拟现实
启动VS:cmd窗口 输入devenv
.sln文件:解决方案文件,包含着整个解决方案的信息,可以双击运行
.csproj文件:项目文件,里面包着着整个项目的信息,可以双击运行
代码所有标点都以英文半角
ORM框架:对象关系映射
SqlSugar (国内)
Dos.ORM (国内)
Chloe (国内)
StackExchange/Dapper (国外)
Entity Framework (EF) (国外)
NHibernate (国外)
ServiceStack/ServiceStack.OrmLite (国外)
linq2db (国外)
Massive (国外)
PetaPoco (国外)
设置 DOS 窗口代码页(Code Page):
设置当前代码页为 UTF-8:chcp 65001
设置当前代码页为 GBK:chcp 936
Vs基本设置
启动:F5
生成解决方案(查看错误代码):crtl + shitf + b
启动项目设置:右键点击解决方案,在属性窗口中
![](https://i-blog.csdnimg.cn/blog_migrate/33fd5ed5ad66d7d3c6df0091d554a728.png)
不用的项目可以卸载,需要使用的时候重新加载
快捷键
快速对齐代码:crtl + k + D
复制鼠标所在行:crtl + D
选中行首和行尾:shift + home shift + end (上下键移动可以选择多行)
多行注释:crtl + shift + /
注释所选代码:ctrl + k + C (使用的是单行注释)
取消注释代码:Ctrl + K + U
折叠冗余代码:#region(空格 说明区域内代码的作用) #endregion 一起使用 //方便代码管理
打开开发文档:F1
返回定义代码:ctrl + -
转小写:Ctrl+ U
转大写:CTRL + SHIFT + U
返回撤销:ctrl + Y
拆分窗口:Alt + w 里面选择拆分(能将一个代码窗口拆成两部分,方便对比)
注释
文档注释:/// 三斜杠 多用来注释类或者方法 (java文档注释: //* 内容 */ )
using System; //命名空间
namespace HelloWorldApplication //项目名称
{
class HelloWorld
{
static void Main(string[] args)
{
/* 我的第一个 C# 程序*/
Console.WriteLine("Hello World");
Console.ReadKey(); /* 暂停程序,等待一个按键操作,按下的任意键将显示在控制台当中(下面没有暂停就是一闪而过) */
string in = Console.ReadLine() //接受用户输入 一般写string类型接受值,但是有需求可以转换
} //convert.Int16(parm);
}
}
数据类型
堆栈和静态存储区
堆:空间比较大,但是读取速度比较慢
能在任意区域插入和删除
栈:空间比较小,但是读取速度比较快
数据只能在栈顶部进行插入和删除,先进后出
变量
变量先声明 再赋值 最后使用
java标识符 是以 下划线、字母、$开头
c#标识符 是以 字母、下划线、@开头
camel 驼峰命名原则:要求变量名首字母单词小写,其余单词首字母大写
Pascal :每一个单词首字母都是大写 用于类名和方法名
局部变量是在函数、复合语句内、for循环中。存储在栈区;
全局变量是在函数外部定义的变量;
成员变量在方法外部,定义在类中,在整个类中可以被访问,成员变量**随着对象的建立消失而定,存在于堆内存当中,有初始值
类型 | 描述 | 范围 |
---|---|---|
decimal | 128 位精确的十进制值,28-29 有效位数 | (-7.9 x 1028 到 7.9 x 1028) / 100 到 28 |
sbyte | 8 位有符号整数类型 | -128 到 127 |
short | 16 位有符号整数类型 | -32,768 到 32,767 |
uint | 32 位无符号整数类型 | 0 到 4,294,967,295 |
ulong | 64 位无符号整数类型 | 0 到 18,446,744,073,709,551,615 |
ushort | 16 位无符号整数类型 | 0 到 65,535 |
var | 它是一个声明变量的占位符。它主要用于在声明变量时,无法确定数据类型时使用。 |
var特点
-
必须在定义时初始化。也就是必须是var s = “abcd”形式,而不能是如下形式: var s; s = “abcd”;
-
一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。
-
var要求是局部变量。
float、double、long类型变量赋值添加F、D、L(大小写均可)尾缀。默认为double类型,float不加 f 报错。
double类型,声明整数为double类型时,需要加后缀 D或d
decimal后缀必须加 M或m,不加则视为double类型
如需得到一个类型或一个变量在特定平台上的准确尺寸,可以使用 sizeof 方法。表达式 sizeof(type) 产生以字节为单位存储对象或类型的存储尺寸。
三种数据类型:值类型 ;引用类型有对象(object)类型、动态(dynamic)类型 、字符串类型;
动态(dynamic)类型可以在动态类型的变量中存储任何类型的值
动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时发生的,而动态类型变量的类型检查是在运行时发生的。
转义字符
/ : 斜杠 \ : 反斜杠
转义字符:一个" \ " 加一个 特殊的字符,组成了一个具有特殊意义的字符
\n 表示换行
\" 表示英文半角双引号
\t 表示一个tab键的空格
\b 表示一个退格键,放在字符串两端没有效果
\r\n 写入文件进window系统时不认识 \n,只认识\r\n
\\ 表示一个\
@符号的作用:
- C# string 字符串的前面可以加 @(称作"逐字字符串")将转义字符(\)当作普通字符对待 ,取消 \ 的转义作用
string str = @"C:\Windows"; 等价于 string str = "C:\\Windows";
//一般用于路径
string path = @"E:\ljx\a-StudyC#\笔记";
- @ 字符串中可以任意换行,换行符及缩进空格都计算在字符串长度之内。 将字符串按照编辑的原格式输出。
System 命名空间中的 Console 类提供了一个函数 ReadLine(),用于接收来自用户的输入,并把它存储到一个变量中。
静态和动态常量
C#静态常量是使用 const 关键字来定义的 。定义一个静态常量的语法如下:
const <data_type> <constant_name> = value;
//静态常量编译时,使用常量的值去替换
int value = <constant_name>
//是使用<constant_name>的值去替换value
C#动态常量是使用 readonly 关键字来定义的 。定义一个动态常量的语法如下:
readonly <data_type> <constant_name> = value;
静态常量和动态常量两者的区别如下:
Java静态常量是使用static final
public static final <data_Type> <constant_name> = value;
// ++a 先进行自增运算再赋值
交换变量
//当面试说不可以使用第三个变量来交换变量时
int n1,n2;
n1 = n1 - n2;
n2 = n1 + n2;
n1 = n2 - n1;
占位符
{0} 挖几个坑 就填几个坑 从0开始 按照填的下标数字顺序输出
输出小数时 {0:0.00} 表示输出两位小数
值传递和引用传递
方法参数传递:默认值传递
运算符
逻辑与比逻辑或优先级高
一般使用逻辑与或逻辑或 ,效率更快 && ||
-
异或运算(^) 也就是说,当且仅当只有一个操作数为 true 时,结果才为 true。
-
& 运算符(与) 两个操作数都为true,结果才为true
-
| 运算符(或) 只要一个操作数为true,结果就为true
-
左移 (<<)
将第一个操作数向左移动第二个操作数指定的位数,空出的位置补0。
左移相当于乘. 左移一位相当于乘2;左移两位相当于乘4;左移三位相当于乘8。 -
右移 (>>)
将第一个操作数向右移动第二个操作数所指定的位数,空出的位置补0。右移相当于整除. 右移一位相当于除以2;右移两位相当于除以4;右移三位相当于除以8。
is 判断对象是否为某一类型。 If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。 as 强制转换,即使转换失败也不会抛出异常。 Object obj = new StringReader(“Hello”); StringReader r = obj as StringReader;
条件语句
if
if-else特点:先判断,再执行,至少都要执行一次代码
注意:else永远跟离他最近的那个if配对
switch语句
switch(变量){
case 条件1:
break;
case 条件2:
break;
default: //都不满足的时候,默认是什么
break;
}
//switch变形
switch(变量){
case 条件1: //当条件一和条件二输出内容一致时
case 条件2:
Console.WriteLine(“两个条件为或,满足一个即可输出”);
}
switch语句,后面跟跳转语句break或者continue 、go to xxx。最后面switch都不满足 default break 。
循环
for循环
下面来看看它的执行过程:
1. 求解表达式1。
2. 求解表达式2。若其值为真,则执行 for 语句中指定的内嵌语句,然后执行第3步;若表达式2值为假,则结束循环,转到第5步。
3. 求解表达式3。
4. 转回上面第2步继续执行。
5. 循环结束,执行 for 语句下面的语句。
using System;
namespace zhishu;
class mathZS
{
public static void Main(string[] args)
{
int i, j;
//Boolean sign = true; 不可以放在循环外面
int count = 0;
for (i = 2; i < 100; i++)
{
Boolean sign = true;
for (j = 2; j < i; j++) {
if (i % j == 0) {
sign = false;
break;
}
}
if (sign) {
count++;
Console.WriteLine("1-100的质数为:{0}",i);
}
}
Console.WriteLine("质数有:{0}位", count);
}
}
foreach语句
int[] fibarray = new int[] { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibarray) //element 元素
do…while 循环与 while 循环类似,但是 do…while 循环会确保至少执行一次循环。
注意:与 for 循环和 while 循环不同,do while 循环需要以分号 ; 结尾。
C# 中的 continue 语句有点像 break 语句。但它不是强迫终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。
goto语句用法
使用 goto 语句来跳转程序,必须先在想要跳转的位置定义好一个标签(Labels),标签名称的定义和变量名类似,然后使用goto 标签名;即可使程序跳转到指定位置执行。
提示:goto 语句并不限于在循环中使用,其它的情况也可以使用。但是,goto 语句不能从循环外跳转到循环语句中,而且不能跳出类的范围。
/* goto Label;
语句块 1;
Label:
语句块 2; */
login:
Console.Writeline("登录啦");
goto login;
Console.WriteLine("登录成功");
封装
封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。
抽象和封装是面向对象程序设计的相关特性。抽象允许相关信息可视化,封装则使开发者实现所需级别的抽象。
一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:
- public:所有对象都可以访问;
- private:对象本身在对象内部可以访问;
- protected:只有该类对象及其子类对象可以访问
- internal:同一个程序集的对象可以访问;
- protected internal:访问限于当前程序集或派生自包含类的类型。 允许在本类,派生类或者包含该类的程序集中访问。这也被用于实现继承。
如果没有指定访问修饰符,则使用类成员的默认访问修饰符,即为 private。
方式 | 描述 |
---|---|
值参数 | 这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。 |
引用参数 | 这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值。//使用 ref 关键字声明引用参数 /* 调用函数来交换值 */ n.swap(ref a, ref b); |
输出参数 | 这种方式可以返回多个值。 //n.getValue(out a); 使用 out 关键字声明引用参数 |
? 单问号用于对 int、double、bool 等无法直接赋值为 null 的数据类型进行 null 的赋值,意思是这个数据类型是 Nullable 类型的。
int i; //默认值0
int? ii; //默认值null 意思是这个数据类型是 Nullable 类型的
double? num3 = new double?();
double? num4 = 3.14157;
bool? boolval = new bool?();
?? 双问号用于判断一个变量在为 null 的时候返回一个指定的值。
Null 合并运算符用于定义可空类型和引用类型的默认值。运算符的左操作数不为 null,那么运算符将返回左操作数,否则返回右操作数。
注:Null 合并运算符左右两边操作数的类型必须相同,或者右操作数的类型可以隐式的转换为左操作数的类型(小转大),否则将编译错误。
num3 = num1 ?? 5.34; // num1 如果为空值则返回 5.34
?.
checktimer?.Dispose();
“评估第一个操作数;如果它为空,则停止,结果为空。否则,评估第二个操作数(作为第一个操作数的成员访问)。”
数组
数组是一个引用类型,所以您需要使用 new 关键字来创建数组的实例。
您创建一个数组时,C# 编译器会根据数组类型隐式初始化每个数组元素为一个默认值。例如,int 数组的所有元素都会被初始化为 0。
//初始化数组并且设定数组大小且赋值
double[] arr1 = new double[4]{96.5, 98.0, 99.5, 90.0};
概念 | 描述 |
---|---|
多维数组 | C# 支持多维数组。多维数组最简单的形式是二维数组。 |
交错数组 | C# 支持交错数组,即数组的数组。 |
传递数组给函数 | 您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。 |
参数数组 | 这通常用于传递未知数量的参数给函数。 |
Array 类 | 在 System 命名空间中定义,是所有数组的基类,并提供了各种用于数组的属性和方法。 |
交错数组:在声明交错数组的时候,只需要指定第一维的长度 int[ ] [ ] arr = new int [ 5 ] [ ];
参数数组:在使用数组作为形参时,C# 提供了 params 关键字,使调用数组为形参的方法时,既可以传递数组实参,也可以传递一组数组元素。params 的使用格式为: public int AddElements (params int[] arr)
ARRAY类最常用的属性 |
---|
IsFixedSize 获取一个值,该值指示数组是否带有固定大小。 |
IsReadOnly 获取一个值,该值指示数组是否只读。 |
Length 获取一个 32 位整数,该值表示所有维度的数组中的元素总数。 |
LongLength 获取一个 64 位整数,该值表示所有维度的数组中的元素总数。 |
**Rank ** 获取数组的秩(维度)。 |
序号 | ARRAY类最常用方法 & 描述 |
---|---|
1 | Clear 根据元素的类型,设置数组中某个范围的元素为零、为 false 或者为 null。 |
2 | Copy(Array, Array, Int32) 从数组的第一个元素开始复制某个范围的元素到另一个数组的第一个元素位置。长度由一个 32 位整数指定。 |
3 | CopyTo(Array, Int32) 从当前的一维数组中复制所有的元素到一个指定的一维数组的指定索引位置。索引由一个 32 位整数指定。 |
4 | GetLength 获取一个 32 位整数,该值表示指定维度的数组中的元素总数。 |
5 | GetLongLength 获取一个 64 位整数,该值表示指定维度的数组中的元素总数。 |
6 | GetLowerBound 获取数组中指定维度的下界。 |
7 | GetType 获取当前实例的类型。从对象(Object)继承。 |
8 | GetUpperBound 获取数组中指定维度的上界。 |
9 | GetValue(Int32) 获取一维数组中指定位置的值。索引由一个 32 位整数指定。 |
10 | IndexOf(Array, Object) 搜索指定的对象,返回整个一维数组中第一次出现的索引。 |
11 | Reverse(Array) 逆转整个一维数组中元素的顺序。 |
12 | SetValue(Object, Int32) 给一维数组中指定位置的元素设置值。索引由一个 32 位整数指定。 |
13 | Sort(Array) 使用数组的每个元素的 IComparable 实现来排序整个一维数组中的元素。 |
14 | ToString 返回一个表示当前对象的字符串。从对象(Object)继承。 |
//用于转化值的格式化方法
DateTime waiting = new DateTime(2012, 10, 10, 17, 58, 1);
string chat = String.Format("Message sent at {0:t} on {0:D}",
waiting);
//结果 Message: Message sent at 17:58 on Wednesday, 10 October 2012
字符串
trim的用法
属性 | 描述 |
---|---|
Trim(Char[]) | 从当前字符串删除数组中指定的一组字符的所有前导匹配项和尾随匹配项。 |
Trim(char) | 从当前字符串删除字符的所有前导实例和尾随实例。 |
Trim() | 从当前字符串删除所有前导空白字符和尾随空白字符。 |
TrimEnd(Char[]) | 删除字符串尾部的空白字符 |
TrimStart(Char[]) | 删除字符串首部的空白字符 |
String类的方法
方法 | 描述 |
---|---|
Clone() | 返回对此 String 实例的引用 |
Compare(String, String) | 比较两个指定的 String 对象,并返回一个指示二者在排序顺序中的相对位置的整数.该方法区分大小写。 |
CompareOrdinal(String, String) | 通过比较每个字符串中的字符,来比较两个字符串是否相等 |
CompareTo(String) | 将一个字符串与另一个字符串进行比较 |
Concat(String, String) | 连接两个指定的字符串 |
Contains(String) | 判断一个字符串中是否包含零一个字符串 |
Copy(String) | 将字符串的值复制一份,并赋值给另一个字符串 |
CopyTo(Int32, Char[], Int32, Int32) | 从字符串中复制指定数量的字符到一个字符数组中 |
EndsWith(String) | 用来判断字符串是否以指定的字符串结尾 |
Equals(String, String) | 判断两个字符串是否相等 |
Format(String, Object) | 将字符串格式化为指定的字符串表示形式 |
GetEnumerator() | 返回一个可以循环访问此字符串中的每个字符的对象 |
GetHashCode() | 返回该字符串的哈希代码 |
GetType() | 获取当前实例的类型 |
GetTypeCode() | 返回字符串的类型代码 |
IndexOf(String) | 返回字符在字符串中的首次出现的索引位置,索引从零开始 |
Insert(Int32, String) | 在字符串的指定位置插入另一个字符串,并返回新形成的字符串 |
Intern(String) | 返回指定字符串的内存地址 |
IsInterned(String) | 返回指定字符串的内存地址 |
IsNormalized() | 判断此字符串是否符合 Unicode 标准 |
IsNullOrEmpty(String) | 判断指定的字符串是否为空(null)或空字符串(“”) |
IsNullOrWhiteSpace(String) | 判断指定的字符串是否为 null、空或仅由空白字符组成 |
Join(String, String[]) | 串联字符串数组中的所有元素,并将每个元素使用指定的分隔符分隔开 |
LastIndexOf(Char) | 获取某个字符在字符串中最后一次出现的位置 |
LastIndexOfAny(Char[]) | 获取一个或多个字符在字符串中最后一次出现的位置 |
Normalize() | 返回一个新字符串,新字符串与原字符串的值相等,但其二进制表示形式符合 Unicode 标准 |
PadLeft(Int32) | 返回一个指定长度的新字符串,新字符串通过在原字符串左侧填充空格来达到指定的长度,从而实现右对齐 |
PadRight(Int32) | 返回一个指定长度的新字符串,新字符串通过在原字符串右侧填充空格来达到指定的长度,从而实现左对齐 |
Remove(Int32) | 返回一个指定长度的新字符串,将字符串中超出长度以外的部分全部删除 |
Replace(String, String) | 使用指定字符替换字符串中的某个字符,并返回新形成的字符串 |
Split(Char[]) | 按照某个分隔符将一个字符串拆分成一个字符串数组 |
StartsWith(String) | 判断字符串是否使用指定的字符串开头 |
Substring(Int32) | 从指定的位置截取字符串 |
ToCharArray() | 将字符串中的字符复制到 Unicode 字符数组 |
ToLower() | 将字符串中的字母转换为小写的形式 |
ToLowerInvariant() | 使用固定区域性的大小写规则将字符串转换为小写的形式 |
ToString() | 将其它数据类型转换为字符串类型 |
ToUpper() | 将字符串中的字母转换为大写形式 |
// 在局部变量中(即在方法体中)可以使用 var 来代替具体数据类型来定义变量
var temp = "C#";
Substring用法
string path = "http:www.baidu.com";
Console.WriteLine(path.Substring( 3 )); //截取掉 htt
//输出为 p:www.baidu.com
结构
结构体是值类型数据结构。它使得一个单一变量可以存储各种数据类型的相关数据。struct 关键字用于创建结构体。
结构的特点:
- 结构可带有方法、字段、索引、属性、运算符方法和事件。
- 结构可定义构造函数,但不能定义析构函数。但是,您不能为结构定义无参构造函数。无参构造函数(默认)是自动定义的,且不能被改变。
- 与类不同,结构不能继承其他的结构或类。
- 结构不能作为其他结构或类的基础结构。
- 结构可实现一个或多个接口。
- 结构成员不能指定为 abstract、virtual 或 protected。
- 当您使用 New 操作符创建一个结构对象时,会调用适当的构造函数来创建结构。与类不同,结构可以不使用 New 操作符即可被实例化。(不能在声明成员属性时对它们进行初始化,静态属性和常量除外;)
- 如果不使用 New 操作符,只有在所有的字段都被初始化之后,字段才被赋值,对象才被使用。
类vs结构
类和结构有以下几个基本的不同点:
- 类是引用类型,结构是值类型。
- 结构不支持继承。
- 结构不能声明默认的构造函数。
析构函数
C# 中的析构函数具有以下特点:
- 析构函数只能在类中定义,不能用于结构体;
- 一个类中只能定义一个析构函数;
- 析构函数不能继承或重载;
- 析构函数没有返回值;
- 析构函数是自动调用的,不能手动调用;
- 析构函数不能使用访问权限修饰符修饰,也不能包含参数。
类的 析构函数 是类的一个特殊的成员函数,当类的对象超出范围时执行。
析构函数的名称是在类的名称前加上一个波浪形(~)作为前缀,它不返回值,也不带任何参数。
析构函数用于在结束程序(比如关闭文件、释放内存等)之前释放资源。析构函数不能继承或重载。
~Line() //析构函数
{
Console.WriteLine("对象已删除");
}
构造函数
静态构造函数
静态构造函数具有以下特性:
- 静态构造函数不使用访问权限修饰符修饰或不具有参数;
- 类或结构体中只能具有一个静态构造函数;
- 静态构造函数不能继承或重载;
- 静态构造函数不能直接调用,仅可以由公共语言运行时 (CLR) 调用;
- 用户无法控制程序中静态构造函数的执行时间;
- 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化类;
- 静态构造函数会在实例构造函数之前运行。
类
new 关键字在这里的作用主要是在程序运行时为类的实例分配内存。
Student Object = new Student();
类的默认访问标识符是 internal,成员的默认访问标识符是 private。
static
我们可以使用 static 关键字把类成员定义为静态的。当我们声明一个类成员为静态时,意味着无论有多少个类的对象被创建,只会有一个该静态成员的副本。
关键字 static 意味着类中只有一个该成员的实例。静态变量用于定义常量,因为它们的值可以通过直接调用类而不需要创建类的实例来获取。静态变量可在成员函数或类的定义外部进行初始化。你也可以在类的定义内部初始化静态变量。
静态函数只能访问静态属性。
枚举
enum enum_name{
enumeration list; //多个值以逗号隔开
}
//默认情况下,枚举类型中的每个成员都为 int 类型,它们的值从零开始,并按定义顺序依次递增。
foreach(Season i in Enum.GetValues(typeof(Season))){ //GetValues
Console.WriteLine("{0} = {1}", i, (int)i);
}
foreach(String s in Enum.GetNames(typeof(Season))){ //GetNames
Console.WriteLine(s);
}
this关键字
1) 使用 this 表示当前类的对象
2) 使用 this 关键字串联构造函数
public Test()
{
Console.WriteLine("无参构造函数");
}
// 这里的 this()代表无参构造函数 Test()
// 先执行 Test(),后执行 Test(string text)
public Test(string text) : this()
{
Console.WriteLine(text);
Console.WriteLine("实例构造函数");
}
//输出 无参构造函数
// text
// 实例构造函数
3) 使用 this 关键字作为类的索引器
4) 使用 this 关键字作为原始类型的扩展方法
继承
一个类可以派生自多个类或接口,这意味着它可以从多个基类或接口继承数据和函数。
C# 中创建派生类的语法如下:
class <派生类> : <基类>
{
...
}
C# 不支持多重继承。但是,您可以使用接口来实现多重继承。
接口
接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。
接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的。添加修饰符会报错
通常接口命令以 I 字母开头 (不是必须的)
接口继承:一个接口可以继承另外一个接口
partial
Partial关键词定义的类可以在多个地方被定义,最后编译的时候会被当作一个类来处理。
多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。
静态多态性 1.函数重载 2.运算符重载
在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定
1.函数重载函数的定义必须彼此不同,可以是参数列表中的参数类型不同,也可以是参数个数不同。不能重载只有返回类型不同的函数声明。
2.运算符重载: 通过关键字 operator 后跟运算符的符号来定义的。
public static Box operator+ (Box b, Box c) {
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
注意:比较运算符必须成对重载,也就是说,如果重载一对运算符中的任意一个,则另一个运算符也必须重载。比如==
和!=
运算符、<
和>
运算符、<=
和>=
运算符。
动态多态性 抽象类
C# 允许您使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。
下面是有关抽象类的一些规则:
- 您不能创建一个抽象类的实例。
- 您不能在一个抽象类外部声明一个抽象方法。
- 通过在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。
当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法。虚方法是使用关键字 virtual 声明的。虚方法可以在不同的继承类中有不同的实现。对虚方法的调用是在运行时发生的。动态多态性是通过 抽象类 和 虚方法 实现的。
命名空间
为了调用支持命名空间版本的函数或变量,会把命名空间的名称置于前面,如下所示:
namespace_name.item_name;
命名空间可以嵌套使用,也就是说我们可以在一个命名空间中再定义一个或几个命名空间
using
using 关键字表明程序使用的是给定命名空间中的名称。
可以使用 using 命名空间指令,这样在使用的时候就不用在前面加上命名空间名称。该指令告诉编译器随后的代码使用了指定命名空间中的名称。
**内嵌命名空间:**命名空间可以被嵌套,即您可以在一个命名空间内定义另一个命名空间
**using语句用法:**在这个代码段中使用了using语句,它的作用是当使用SqlConnection类的实例时无论什么原因,离开这个代码段就自动调用SqlConnection类的Dispose。使用try……catch也能达到同样的目的,但是using更为方便一点。也可以这样理解:using(SqlConnection con = new SqlConnection(strCon))这句代码的意思是控制对于数据库的关闭和释放,如果是其他的内容也是同理。
在本代码中,如果using下的代码段产生错误,直接结束整段using下的代码,并且关闭数据库并释放资源。类似于try……catch,但是更为高级。因为在try……catch中如果产生某句代码产生异常,会在该句产生一个断点,中断于此并抛出异常。而且如果要释放资源,需要在catch中声明和定义。但是using会自动的释放掉这些占用的资源。
预处理器指令
预处理器指令 | 描述 |
---|---|
#define | 用于定义一系列字符,可以将这些字符称为符号 |
#undef | 用于取消一个已定义符号 |
#if | 用于测试符号是否为真 |
#else | 用于创建复合条件指令,与 #if 一起使用 |
#elif | 用于创建复合条件指令 |
#endif | 指定一个条件指令的结束 |
#line | 用于修改编译器的行数以及(可选地)输出错误和警告的文件名 |
#error | 用于在代码的指定位置生成一个错误 |
#warning | 用于在代码的指定位置生成一级警告 |
#region | 用于在使用 Visual Studio Code Editor 的大纲特性时,指定一个可展开或折叠的代码块 |
#endregion | 用于标识 #region 块的结束 |
可以使用 #if 来创建条件指令,条件指令可以用于测试一个或多个符号的值是否为 true 。如果符号的值为 true,那么编译器将评估 #if 指令和下一个指令之间的所有代码。
#define PI //用来定义一个字符
#if (PI)
// 要执行的代码
#elif (PI)
// 要执行的代码
#else
// 要执行的代码
#endif //以 #if 指令开头的条件指令必须以 #endif 指令显式结束。
异常
C# 异常是使用类来表示的。C# 中的异常类主要是直接或间接地派生于 System.Exception 类。System.ApplicationException 和 System.SystemException 类是派生于 System.Exception 类的异常类。
System.SystemException 类是所有预定义的系统异常的基类。
自行定义异常类,自定义的异常类都应继承 System.ApplicationException 类。
异常是在程序运行出错时引发的,例如以一个数字除以零,所有异常都派生自 System.Exception 类。异常处理则是处理运行时错误的过程,使用异常处理可以使程序在发生错误时保持正常运行。
IO
FileStream 类
FileStream 类在 System.IO 命名空间下,使用它可以读取、写入和关闭文件。创建 FileStream 类对象的语法格式
FileStream <object_name> = new FileStream(<file_name>, <FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
参数说明如下:
- object_name:创建的对象名称;
- file_name:文件的路径(包含文件名在内);
- FileMode:枚举类型,用来设定文件的打开方式,可选值如下:
- Append:打开一个已有的文件,并将光标放置在文件的末尾。如果文件不存在,则创建文件;
- Create:创建一个新的文件,如果文件已存在,则将旧文件删除,然后创建新文件;
- CreateNew:创建一个新的文件,如果文件已存在,则抛出异常;
- Open:打开一个已有的文件,如果文件不存在,则抛出异常;
- OpenOrCreate:打开一个已有的文件,如果文件不存在,则创建一个新的文件并打开;
- Truncate:打开一个已有的文件,然后将文件清空(删除原有内容),如果文件不存在,则抛出异常。
- FileAccess:枚举类型,用来设置文件的存取,可选值有 Read、ReadWrite 和 Write;
- FileShare:枚举类型,用来设置文件的权限,可选值如下:
- Inheritable:允许子进程继承文件句柄,Win32 不直接支持此功能;
- None:在文件关闭前拒绝共享当前文件,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败;
- Read:允许随后打开文件读取,如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求都将失败,需要注意的是,即使指定了此标志,仍需要附加权限才能够访问该文件;
- ReadWrite:允许随后打开文件读取或写入,如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求都将失败,需要注意的是,即使指定了此标志,仍需要附加权限才能够访问该文件;
- Write:允许随后打开文件写入,如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求都将失败,需要注意的是,即使指定了此标志,仍可能需要附加权限才能够访问该文件;
- Delete:允许随后删除文件。
属性
抽象类可拥有抽象属性,这些属性应在派生类中被实现。
public abstract string Name
{
get;
set;
}
委托
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。
class Program
{
//委托的参数和返回值类型必须和函数一致
delegate double runDelegate(double parm1,double parm2); //定义委托
static double Multiply(double parm1, double parm2)
{
return parm1 * parm2;
}
static double Divide(double parm1, double parm2)
{
return parm1 / parm2;
}
static void Main(string[] args)
{
runDelegate delegate1; //初始化一个委托
delegate1 = Multiply; //将函数名赋予给委托
Console.WriteLine(Multiply(1,2)); //打印
Console.ReadKey();
}
}
Lambda表达式
在Lambda表达式中,输入参数是Lambda运算符的左边部分。它包含参数的数量可以为0、1或者多个。只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略。输入参数的数量大于或者等于2时,Lambda表达式左边的一对小括弧中的多个参数质检使用逗号(,)分割。
()=>Console.WriteLine("This is a Lambda expression."); //0个参数
m=>m*2; 等价于 (m)=>m*2 //1个参数
() => {};
(n,m) => {}; //多个参数
Implicit和Explicit
Implicit
关键字用于声明隐式的用户定义类型转换运算符。如果可以确保转换过程不会造成数据丢失,则可使用该关键字在用户定义类型和其他类型之间进行隐式转换。隐式转换可以通过消除不必要的类型转换来提高源代码的可读性。 但是,因为隐式转换不需要程序员将一种类型显式强制转换为另一种类型,所以使用隐式转换时必须格外小心,以免出现意外结果。 一般情况下,隐式转换运算符应当从不引发异常并且从不丢失信息,以便可以在程序员不知晓的情况下安全使用它们。 如果转换运算符不能满足那些条件,则应将其标记为 explicit。
//没有使用Implicit
public class DateTimeRange
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public DateTimeRange(DateTime startTime, DateTime endTime)
{
StartTime = startTime;
EndTime = endTime;
}
}
(timeRange.EndTime - timeRange.StartTime).TotalHours; //使用 获取小时
//使用Implicit
public class DateTimeRange
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public DateTimeRange(DateTime startTime, DateTime endTime)
{
StartTime = startTime;
EndTime = endTime;
}
//operator 后面跟需要转换的类型
public static implicit operator double(DateTimeRange timeRange)
{
return (timeRange.EndTime - timeRange.StartTime).TotalHours;
}
}
double hours = timeRange;//使用Implicit 隐式类型转换
double hours = (double)timeRange;//使用Explicit 显示类型转换
Explicit
explicit 关键字用于声明必须使用强制转换来调用的用户定义的类型转换运算符
线程
程序执行的最小单位,响应操作的最小执行流,线程也包含自己的计算资源,线程是属于进程的,一个进程可以有多个线程 。
// Action 是系统内置(或者说预定义)的一个委托类型,它可以指向一个没有返回值且没有参数的方法。
Action<String> action = this.method; //可以使用泛型指定类型
action.invoke();//同步的 单线程
var asyncResult = action.BeginInvoke("调用接口",null,null);
asyncResult.AsyncWaitHandler.WaitOne();//阻塞当前线程,直到收到信号量 ,无延迟
asyncResult.AsyncWaitHandler.WaitOne(-1);//一直等待
asyncResult.AsyncWaitHandler.WaitOne(1000);//阻塞当前线程,等待且最多等待1000ms,做超时控制.
多线程三大特点
使用多线程时,不要通过延时的方式去掌控顺序,不要试图“风骚的多模式”掌控顺序
-
不卡界面
同步单线程方法卡界面 : 主( UI )线程忙于计算,所以不能响应
异步多线程方法不卡界面 : 计算任务交给子线程,主( UI )线程已闲置,可以响应别的操作
-
资源换性能
多线程使用资源换取性能,但并不是线性增长
多线程的协调管理额外成本;资源也是有上限的
-
无序性
不可确定性。启动无序;
执行时间不确定:同一个线程同一个任务耗时也可能不同,其实跟操作系统调度策略有关,CPU分片(1s分成1000份),任务执行顺序看运气 线程优先级
//监控业务,在任务操作完成以后记录日志 Action<string> action = this.method; AsyncCallback callback = ar => { Console.WriteLine(ar.AsyncState); Console.WriteLine("日志"); }; action.BeginInvoke("xxxx",callback,"state");
异步多线程区别与联系
Task、Async、Await
Task
Task类表示不返回值并且通常以异步方式执行的单个操作。 Task对象是在 .NET Framework 4 中首次引入的 基于任务的异步模式的中心组件之一。
Task在线程池线程上异步执行,可以通过Status属性以及 、IsCompleted 和 IsFaulted 属性来确定Task任务的状态。
等待当前线程执行完成后再往下执行。
-
当执行返回参数为Task或者Task<>类型的函数时,假如该函数没有用async标识,那么开启线程执行方法
-
当有async标识时,当前线程会把该方法当成同步函数执行,直到运行到await关键字的地方,开启新线程(此时假如中途执行另一个Task标识的方法,不管该方法是不是async,都会同步执行,不会开启新线程, 但是加入把一个task得方法放到变量中,会开启新的线程
-
await关键字表示会开辟新线程来执行后面的方法,但是该线程会等待新线程执行完返回,然后继续执行
函数的执行途中是根据await关键字来判断是否需要开辟线程来执行代码(Async void方法调用时不能加await,所以它必定是在主线程中被调用),假如被调用的method前面有await,那么这个method必须包含async关键字,假如一个async标识的方法里面没有await,那么这个方法会被当成同步方法来调用
-
Async void 主要用于异步事件处理方法,其他时候请不要使用,在async void方法中,一定要加try catch来捕捉异常。
C#提供Async和Await关键字来实现异步编程。
public static async void T2()
{
return await Task.run(()=>{
语句;
});
}
await/async:是个新语法,不是一个全新的异步多线程使用方式
async可以随便添加,await不可以
await只能出现在task前面,并且方法必须声明async,不能单独出现
await/async 原本没有返回值的,可以返回Task
原本返回 X 类型的,可以返回Task<X>
System.Timers.Timer
工具箱-组件-Timer 设置属性
定时器,带有生成重复事件的选项,默认是在线程池线程中引发事件。适用于作为基于服务器的使用或在多线程环境。
AutoReset:自动重置,默认为值true,true表示每次间隔结束后都会引发一次Elapsed事件,false表示仅在首次时间间隔后引发一次Elapsed事件。
Elapsed:时间间隔后触发的时间。
Intervel:获取两次Elapsed事件的时间间隔,以毫秒为单位,默认值为100毫秒。
Enabled: 表示定时器处于启用状态
Start:启动定时器。
Stop:停止定时器。
checktimer = new System.Timers.Timer(500); //设置间隔多少毫秒执行
checktimer.Elapsed += CheckDevices; //timer.Elapsed += 需要方法名称。设置执行的事件–Elapsed
checktimer.AutoReset = true;
checktimer.Enabled = true;
checktimer.Start();
事件
在类的内部声明事件,首先必须声明该事件的委托类型。例如:
public delegate void BoilerLogHandler(string status);
然后,声明事件本身,使用 event 关键字:
// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;
Winform
C# 函数参数object sender, EventArgs e
object sender:表示触发事件的控件对象
EventArgs e:表示事件数据的类的基类
sender参数用于传递指向事件源对象的引用。简单来讲就是当前的对象。例如button的点击事件,那么这个sender就代表这个button自己。
由于sender指的是事件源对象,sender是object类型,用的时候记得转一下类型才可以用。
e参数是是EventArgs类型。简单来理解就是记录事件传递过来的额外信息。一般用于传递用户点击的位置啊,键盘按下的键等事件的额外信息。
窗体常用属性
属性 | 作用 |
---|---|
Name | 用来获取或设置窗体的名称 |
WindowState | 获取或设置窗体的窗口状态,取值有3种,即Normal(正常)、Minimized(最小化)、Maximized(最大化),默认为 Normal,即正常显示 |
StartPosition | 获取或设置窗体运行时的起始位置,取值有 5 种,即 Manual(窗体位置由 Location 属性决定)、CenterScreen(屏幕居中)、WindowsDefaultLocation( Windows 默认位置)、WindowsDefaultBounds(Windows 默认位置,边界由 Windows 决定)、CenterParent(在父窗体中居中),默认为 WindowsDefaultLocation |
Text | 获取或设置窗口标题栏中的文字 |
MaximizeBox | 获取或设置窗体标题栏右上角是否有最大化按钮,默认为 True |
MinimizeBox | 获取或设置窗体标题栏右上角是否有最小化按钮,默认为 True |
BackColor | 获取或设置窗体的背景色 |
BackgroundImage | 获取或设置窗体的背景图像 |
BackgroundImageLayout | 获取或设置图像布局,取值有 5 种,即 None(图片居左显示)、Tile(图像重复,默认值)、Stretch(拉伸)、Center(居中)、Zoom(按比例放大到合适大小) |
Enabled | 获取或设置窗体是否可用 |
Font | 获取或设置窗体上文字的字体 |
ForeColor | 获取或设置窗体上文字的颜色 |
Icon | 获取或设置窗体上显示的图标 |
AutoScaleMode | None : 禁用自动缩放。(默认时) Font :根据类使用的字体(通常为系统字体)的维度控制缩放。 Dpi : 根据显示分辨率控制缩放。常用分辨率为 96 和 120 DPI。 Inherit : 根据类的父类的缩放模式控制缩放。如果不存在父类,则禁用自动缩放。 |
窗体事件
在窗体中除了可以通过设置属性改变外观外,还提供了事件来方便窗体的操作。窗体中常用的事件如下表所示。
事件 | 作用 |
---|---|
Load | 窗体加载事件,在运行窗体时即可执行该事件 |
MouseClick | 鼠标单击事件 |
MouseDoubleClick | 鼠标双击事件 |
MouseMove | 鼠标移动事件 |
KeyDown | 键盘按下事件 |
KeyUp | 键盘释放事件 |
FormClosing | 窗体关闭事件,关闭窗体时发生 |
FormClosed | 窗体关闭事件,关闭窗体后发生 |
注册事件:双击控件注册的都是控件默认被选中的那个事件
窗体方法
定义的窗体都继承自 System.Windows.Form 类,能使用 Form 类中已有的成员,包括属性、方法、事件等。
实际上窗体中也有一些从 System.Windows.Form 类继承的方法,如下表所示。
方法 | 作用 |
---|---|
void Show() | 显示窗体 |
void Hide() | 隐藏窗体 |
DialogResult ShowDialog() | 以对话框模式显示窗体 |
void CenterToParent() | 使窗体在父窗体边界内居中 |
void CenterToScreen() | 使窗体在当前屏幕上居中 |
void Activate() | 激活窗体并给予它焦点 |
void Close() | 关闭窗体 |
当前窗体需要调用方法直接使用this
关键字代表当前窗体,通过this.方法名 (参数列表)
的方式调用即可。
FormClosing 和 FormClosed的区别
当窗口关闭时,它会引发两个事件:Closing 和 Closed。
Closing 在窗口关闭之前引发,它提供一种机制,可以通过这种机制来阻止窗口关闭。 系统会向Closing 事件处理程序传递一个 FormClosingEventArgs e,该参数实现 Boolean Cancel 属性,将该属性设置为 true 可以阻止窗口关闭。 //e.Cancel = true; 不关闭窗口
如果未处理Closing,或者处理但未取消,则窗口将关闭。 在窗口真正关闭之前,会引发 Closed,这时无法阻止窗口关闭。
窗体控件
名字 | 作用 |
---|---|
MessageBox | 向用户提示操作时也是采用消息框弹出的形式。 |
Label | 分为Label和LinkLabel |
TextBox | 文本框。WordWrap:指示文本框是否换行 PasswordChar:让文本框显示一个单一的字符 ScollBars:是否显示滚动条 事件:TextChanged 当文本框中的内容发生改变时触发 |
Button | 按钮,提交页面内容,或者是确认某种操作 |
RadioButton | 单选按钮操作。多个 RadioButton 控件可以为一组,这一组内的 RadioButton 控件只能有一个被选中。 |
CheckBox | 复选框 |
CheckListBox | 多个选项操作时比较方便 |
ListBox | 列表框将所提供的内容以列表的形式显示出来,可以选择一项或多项 |
ComboBox | 下拉列表框 |
Timer | 在指定的时间间隔内做一件指定的事情 |
MessageBox.Show(Text,Title,Button,MessageBoxlcon);
参数1:弹出框要显示的内容
参数2:弹出框的标题
参数3:也可写作MessageBoxButtons,弹出框的按钮格式
参数4:弹出框的图标样式
注意: 4个参数除了Text外都可以省略,Text也可以用""输出无内容提示框
Button 各枚举常量及意义
Ok | 消息框中只有"确定"按钮 |
---|---|
OkCancel | 消息框中只有"确定"和"取消"按钮 |
YesNo | 消息框中只有"是"和"否"按钮 |
YesNoCancel | 消息框中有"是","否"和"取消"按钮 |
RetryCancel | 消息框中有"重试"和"取消"按钮 |
AbortRetryIgnore | 消息框中有"中止","重试"和"忽略"按钮 |
常量 | 功能及意义 |
Icon各枚举常量及意义
枚举常量 | 功能意义 |
---|---|
Error | 消息框中有一个符号,由一个红色背景的圆圈及其中的白色X组成 |
Asterisk | 该符号是由一个圆圈及其中的小写字母i组成 |
Exclamation | 该符号由一个黄色背景的三角形及其中的一个叹号组成 |
Hand | 该符号由一个红色背景的圆圈及其中的白色x组成 |
Question | 该符号由一个圆圈及其中的一个问号组成 |
None | 消息框中不包含符号 |
Information | 该符号是由一个圆圈及其中的小写字母i组成 |
Stop | 该符号是由一个红色背景的圆圈及其中的白色X组成 |
Warning | 该符号是由一个黄色背景的三角形及其中的一个叹号组成 |
MessageBox.Show("设备连接中","标题",MessageBoxButtons.OK,MessageBoxIcon.Information);
C#小记
随记
访问微软网站,设置dns地址
![](https://i-blog.csdnimg.cn/blog_migrate/ac0d326fd9a259042e394fbcba8565a5.png)
输入登陆用户名和密码时,用字符串string接受,不需要转数字
代码分块很多的时候
可以使用define 、if 、 end if 、region、endregion