学习笔记-C#(重点是第五章)
第一章 c#语言概述
1.1c#语言的特点
- 完全面向对象的语言,只允许单继承即一个类只有一个基类。不存在全局函数,全局变量。
所有函数(方法),变量和常量必须定义在类中,也避免了命名冲突
- 与web紧密结合——简化web开发
- 充分的安全性与错误处理——例如不能使用未初始化的变量,不支持不安全的指向,不能将整数指向引用类型等等
- 灵活性——使用委托模拟一部分指针功能
- 兼容性——c#语言组件与其他语言组件间的互操作性
1.2 .NET Framework
- .NET Framework是一种面向网络支持各种用户终端的开发环境
- 托管代码(在.net 的公共语言运行库CLR 控制下运行,可自动垃圾回收,类型检查和安全支持)与非托管代码(不在。。。下运行。没有。。。功能)
- .net 组成:FCL和CLR
FCL是一个非常全面的类库,由命名空间组成,
命名空间里又包含可在程序中使用的类,结构,枚举,委托和接口等。
常见的命名空间(备注:一开始看很复杂,后面发现这些是用于各个方面的东西,不急于短时间全搞懂)
System命名空间:包含类和基类,这些类定义常用的值和引用数据类型,事件和事件处理程序,接口,属性和异常处理。
System.Windows命名空间:包含在WPF应用程序中使用的类型,包括动画客户端,用户界面控件,数据绑定和类型转换。System.Windows.Forms及其子命名空间用于开发Windows窗体应用程序。
System.Web命名空间:包含启用浏览器/服务通信的类型。
System.Data命名空间:包含访问和管理多种不同来源的数据的类
System.IO命名空间:包含支持输入和输出的类
System.Linq命名空间:包含支持使用语言集成查询(LINQ)的类
CLR是.NET 的核心组件,主要由CLS和CTS组成。
-----CLS是最低标准集,程序必须遵守这个标准编写
CTS可以实现跨语言功能
- C#编译两次才能在本机上运行,第二次使用JIT编译器
MISL:一种与机器无关的中间语言,是独立于cpu之外的指令集,它可以被高效地转换为本机机器代码
1.3 一个简单的C#程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//控制台默认的引用部分,如同C语言里的头文件//
namespace proj1_1 //命名空间//
{
class program //定义类//
{
static void Main(string[] args)
{
int a,b,c;
Console.Write("a:");
a = int.Parse(Console.ReadLine());
//ReadLine()用于获取从键盘上输入的一段字符串,若只有一个字符,可以使用Read()//
Console.Write("b:");
b = int.Parse(Console.ReadLine());
c = a + b;
Console.WriteLine("a+b={0}",c);
//WriteLine()输出的字符串后面自带一个换行符,而不需要换行的话用Write()//
}
}
}
默认命名空间和项目名一致
注意:输出(WriteLine())
eg.{0,5:c},123.456 输出:¥123.46
这个0代表后面的第一个数据,5代表输出5个数字,c代表将数据转成货币形式。
·····常见的还有(不区分大小写)
d:整数类型
e:科学计数法类型
f:浮点数据类型
g:通用格式类型
n:自然数类型
x:十六进制类型
- 数据的转化
int.Parse() int类的Parse方法
同样有
···single.Parse()
…double.Parse()
第二章 c#程序设计基础
2.1标识符
和其他编程语言有着类似的规定
- 标识符只能以数字,字母和下划线组成,开头只能以数字和下划线
- 严格区分大小写(大写和小写是两个元素)
- 不能和关键字,和c#中类库的名字相同。
关键字 | ||||
---|---|---|---|---|
abstract | as | base | bool | break |
byte | case | catch | char | checked |
class | const | continue | deecimal | default |
delegate | do | double | else | enum |
event | explicit | extern | false | finally |
fixed | float | for | foreach | goto |
if | implict | in | int | interface |
internal | is | lock | long | namespace |
new | null | object | operator | out |
override | params | private | protected | public |
readonly | ref | return | sbyte | sealed |
short | sizeof | stackalloc | static | string |
struct | switch | this | throw | true |
try | typeof | uint | ulong | unchecked |
unsafe | ushort | using | virtual | void |
volatile | while |
2.2c#中的数据类型(初次尝试使用mermaid,不知道怎么去掉每类后面几行)
在c#中,int a = 2<3 是❌的
而 bool a = 2<3 是 ✔ 的
objec类可以赋给任何类型的值
eg. object f = 1.23;
object obj2 = “China”;
带@的字符串被认为是严格字符串
eg.string str3 = @“China\n”;
此时里面的’\n’将作为字符串的成员输出
2.3 内存空间:栈空间与堆空间
栈空间:
存储值类型数据,先进后出的数据结构,且由系统管理所有栈空间操作,当一个数据出栈后其空间由系统收回。
堆空间:存储引用类型数据,堆空间可以以任意顺序存入和移除数据。
CLR的垃圾回收器在判断程序的代码不会再访问某数据时自动清除无用的堆数据对象
c#中没有指针,而改为引用,使用new为其分配空间。
C语言中指针既可以指向相应类型的某个变量,也可以指向未被命名的对象
而c#引用类型变量指向的类型都是没有名称的
int []a = new int[3]{1,2,3}; //定义一个数组
for(int i = 0; i < 3;i++)
Console.Write("{0}",a[i]);
Console.WriteLine();
int []b = a;//定义数组b,并赋值a,将a复制给b其实也是将数组a在堆空间中的地址分配给b
for(int i = 0; i < 3;i++)
b[i]*=2;
for(int i = 0; i < 3;i++)
Console.Write("{0}",a[i]);//输出结果为: 2,4,6 即a内元素发生变化
Console.WriteLine();
eg. string S1 = null; //仅在栈空间中分配空间,不需要在堆空间中分配任何对象
string S2 = “” ; //既占栈空间又占堆空间
2.4 常量
直接常量,符号常量
… 无后缀c#自动判断一个数值常数的类型的顺序为:
1.不带小数点–>整数
2.整型–>按int uint long ulong 顺序判断
3.带小数点–>浮点型中的double
…有后缀 | |
---|---|
u(U) | uint ulong 按大小决定 |
l (L) | long ulong 按大小决定 |
ul | ulong |
f (F) | float |
d(D) | double |
m(M) | decimal |
- 符号常量
使用const
eg. const double PI = 3.14159265;
2.5 类型转换:
- 隐式转换
(不需要加以声明就可以转换eg. int -->long 即小转大) - 显式转换
(需要用户明确地指定转换类型,eg. (int)1.23 )
2.6 装箱和拆箱:实现值类型和引用类型地转换
- 装箱转换:(值–>引用)
eg. int i = 10; //在栈中
object obj = i; //这里是隐式转换
也可以写成: object obj = (object)i;
变量i及其值10是在栈空间中分配的,obj是引用类型变量也是在栈空间中分配的,当i装箱后变成引用类型数据,在堆中分配空间,obj中包含其地址。
- 拆箱转换:(引用–>值)
eg. object obj = 10;
int i = (int)obj; (拆箱转换必须显式转换)
为了更直观理解,此处取课本一张截图
(其实是我不知道怎么用markdown画这个图😂)
2.7结构类型和枚举类型
- 结构类型(和C语言类似)
此处以一个例子粗浅理解
struct Student
{
public int xh;
public string xm;
//public 是指可以通过该类型变量访问该字段
//private(默认:即如果没修饰符):不可以。。。
}
Student S1,S2;
也可以用引用变量
eg.Student S1 = new Student();
- 枚举类型
enum Color {Red,Greem,Blue,White,Black};
//默认第一个为0,后面依次加一
>**注意**
>若是赋值这么做
>enum Color {Red=0,Green,Blue=3,White,Black=1}
>此时Green=1,但是White=4,即是在前一位的基础上加一;
定义变量:Color C1;
变量赋值:C1 = Color.Red;
下面有个例子说明:直接输出枚举类型数据输出的是字符串类型,要数值需要进行强制转换
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
namespace program
{
class Program
{
enum Color { Red = 5, Green, Blue, White = 1, Black }
static void Main()
{
Color C1, C2;
Console.WriteLine("{0},{1},{2},{3},{4}", Color.Red, Color.Green, Color.Blue, Color.White,Color.Black);
//输出结果为:Red,Green,Blue,White
Console.WriteLine("{0},{1},{2},{3},{4}", (int)Color.Red, (int)Color.Green, (int)Color.Blue, (int)Color.White, (int)Color.Black);
//输出结果为:5,6,7,2
C1 = Color.Red;
C2 = C1 + 1;
Console.WriteLine("{0},{1}",C2,(int)C1);
//输出结果为Green,5
}
}
}
2.8C#运算符和表达式
- 字符串运算符
只有一个 加号(+) 用于将字符串合并
eg. string S =“Hello”;
S = S + “World”;
Console.WriteLine(S); ——输出:Hello Wrold
- 复合运算符
&= | 与赋值 |
^= | 异或赋值 |
|= | 或赋值 |
- typeof 运算符
- 输出结构类型的程序(项目名)
eg. 在proj2-2 中声明了Student结构
则 Console.WriteLine(typeof(Student));
输出:proj2-2.Program+Student
- check和uncheck
用于对整形算术运算符和转换显示启用溢出检查
eg. int i = int.Maxvalue +10 // int.Maxvalue 是int的最大值
Console.WriteLine(i);
//此时会检测溢出,编译错误
int n = 10;
int i = Maxvalue + n;
Console.WriteLine(i);
//不会检查出错误,会输出2147483639作为结果
使用 int n = 10;
Console.WriteLine(checked(int.Maxvalue + n));
//在运行时会检测求和计算导致的溢出
2.9 C#中常用类和结构
-
int 类-提供属性和方法
int n (n->对象) -
string类
功能 | 方法 | 实现 |
---|---|---|
比较字符串 | Compare(静态方法) | String.Compare(String str1,String str2,boolean ignoreCase) 当str1>str2,返回一个正整数,当str1<str2时,返回一个负整数,当str1=str2,返回0;备注:ignoreCase可以省略,功能是指出是否需要考虑大小写,为true表示不考虑,为false是考虑. |
CompareTo(非静态方法) | str1.CompareTo(str2) | |
求子串位置 | IndexOf | String S1 = “abc”;String S2 = “bc”; char c = ‘c’;Console.WriteLine(“{0},{1}”,S1.IndexOf(S2),S1.IndexOf©); 结果输出1,2 输出第一个匹配项的位置 |
格式化字符串 | Format(静态方法) | 使用方法和WriteLine类似 String S1=“abc”;String S2 = “cde”;String.Format(“串1:{0},串2:{1}”,S1,S2); 输出结果:串1:abc,串2:cde 前面的{}为占位符,Format方法将后面的对象格式化成String填充到前面的占位符里; |
分割字符串 | Split | String S1 = “abc,d,1,45”;String[]str2 = new String[10] //声明字符数组 char []sp ={‘,’}; str2 = str1.Split(sp); //str2[0] =“abc”, str2[1]=“d”,str2[2]=“1”,str[3]=“45” 备注:sp是指用于分割的字符标志 |
- Math类
都是静态方法
eg. Math.Floor() // 返回小于或等于指定数字的最大整数
Math.Sign() // 返回表示数字符号的值
Math.Round() // 将值舍入到最接近的整数或指定的小数位数
其他的方法大都是学过的数学函数方法,如三角函数,指数函数,幂函数,开根号等等
- Convert类
将一个值类型转换成另一个值类型
方法 | 说明 |
---|---|
ToBoolean | 将数据转换成Boolean类型 |
ToDateTime | 成日期时间类型 |
ToInt16 | 成16位整数类型 |
ToInt32 | 成32位整数类型 |
ToInt64 | 成64位整数类型 |
ToNumber | 成double类型 |
ToObject | 成object类型 |
ToString | 成string类型 |
静态方法和非静态方法的区别
静态方法的使用:类名.方法
非静态方法的使用:对象名.方法
DateTime结构(课本里介绍很多,考试不考吧。。以后需要补充)
第三章 c#控制语句
和其他语言大同小异
- if
- if…else
- if…else if
- switch
- while
- do…while
- for
补充:嘿嘿,这个foreach是c#特有的,笔记我就放在第四章
- break:从当前的循环语句(do,while和for)中跳出来,执行后面的程序
- continue:结束这次循环,不执行该次循环以后的程序,直接进入下一次循环。
- goto(比较少用)
格式:目标程序前加一个标号,goto 标号//跳转到目标程序
eg. end:Console.Write(0);
if(1<3) goto end;
第四章 数组与集合
4.1 一维数组
-
定义:eg. int []a; double []b;——静态定义
或者:int []b = new int[]{1,2,3,4}——动态定义 -
访问一维数组
int []e = {1,2,3,4};
foreach(int i in e)
System.Console.Write("{0}",i);
Console.WriteLine();
WriteLine() 是一个自带换行符的
Write() 是不带换行符的
- 数组越界提示
未处理的异常:Sysytem.IndexOutOfRangeException:索引超出了数组界限
4.2 二维数组
-
定义:int[,]b;
或者:int[,]b={{1,2,3},{4,5,6}}; -
访问:int[,] c=new int [2,3]{{1,2},{3,4},{5,6}};
foreach(int e in c)
System.Console.Write(“{0}”,i);
Console.WriteLine(); -
交错数组
特点:没一子数组都是独立的多维数组
eg.int[][]a = new int [3][]; //由三个元素组成的交错数组,其中每个元素都是一个一维数组
初始化:
a[0] = new int[5];
a[1]= new int[4];
a[2] = new int[2];
还可以 a[0] = new in[]{1,2,3,4,5};
a[1]=new int[]{6,7,8,9};
a[2]=new int[]{10,11};
也可以:
int[][]b = new int[][]{new int[]{1,2},new int[][]{3,4},new int[]{5,6}};
- 访问交错数组
int [][]d = new int[3][];
d[0] = new int[]{1,2,3};
d[1] = new int[]{4,5,6};
d[2] = new int[]{7,8,9};
for(int i = 0;i<d.Length;i++)
{
Console.Write("d({0}):",i);
for(int j=0;j<d[i].Length;j++)
{
Console.Wriet("{0} ",d[i][j]);
}
Console.WriteLine();
}
输出结果:
d{0}=1 2 3
d{1}=4 5 6
d{2}=7 8 9
4.4 Array类
Array类是抽象类,不能创建它的对象
但是它提供了一些方法
方法 | 方法类别 | 说明 |
---|---|---|
静态方法 | Copy | 将一个Array的一部分元素复制到另一个Array中,并根据需要执行类型强制转换和装箱 |
IndexOf | 返回一维Array或部分Array中某个值的第一个匹配值的索引 | |
Resize | 将数组的大小转换成指定的新大小 | |
Reverse | 反转一维Array或部分Array中元素的顺序 | |
Sort | 对一维Array对象中的元素进行排序 | |
Find | 搜索与指定的谓词定义的条件匹配的元素,然后返回整个Array中的第一个匹配项 | |
动态方法 | CopyTo | 将当前的一维数组中的全部元素复制到指定一维Array中 |
GetLength | 获取一个32位整数,该整数表示Array中指定维中的元素数 | |
GetLongLength | 获取一个64位整数。该整数表示Array中指定维中的元素数 | |
GetLowerBound | 获取指定维度的下限 | |
GetUpperBound | 获取指定维数的上限 | |
GetValue | 获取当前Array元素中指定元素的值 | |
SetValue | 将当前Array中指定元素设置为指定值 |
补充笔记:这里的Sort的方法是有一个特别的地方
Array.Sort(Array1,Array2); //对两个一维数组进行排序:此时两个数组是联系的,即前一个数组排序变动元素时,第二数组中元素也跟着同步变动。 应用:用于数据排序,如:对学生的成绩排序时需要根据某一个部分进行排序,那么学生名字也需要跟着一起变化。
//4.4 Array类静态方法Sort对两个数组排序的应用
static void Main()
{
int[][] shuzhu = new int[2][];
shuzhu[0] = new int[]{1,2,3,4,5,6};
shuzhu[1] = new int[]{97,33,95,45,102,51 };
Console.WriteLine("排序前:");
for(int i=0;i<shuzhu.Length;i++)
{
Console.Write("shuzhu{0}= ", i);
for(int j = 0; j < shuzhu[i].Length;j++)
{
Console.Write("{0} ", shuzhu[i][j]);
}
Console.WriteLine();
}
Array.Sort(shuzhu[1], shuzhu[0]);
Console.WriteLine("排序后:");
for (int i = 1; i >=0; i--)
{
Console.Write("shuzhu{0}= ", i);
for (int j = 0; j < shuzhu[i].Length; j++)
{
Console.Write("{0} ", shuzhu[i][j]);
}
Console.WriteLine();
}
}
输出结果:
排序前:
shuzhu0= 1 2 3 4 5 6
shuzhu1= 97 33 95 45 102 51
排序后:对象
shuzhu1= 2 4 6 3 1 5
shuzhu1= 33 45 51 95 97 102
4.5 ArrayList类
类比成:Array类的优化,对象是可以创建自己的对象
- 定义ArrayList类的对象
ArrayList myarry = new ArrayList();
区别:
- Array的容量和和元素个数是固定的,而ArrayList的容量是可以按需动态扩展的
- ArrayList提供的方法可以在集合中追加,插入或移除一组元素,而Array中一次只能对一个元素进行操作。
- ArrayList中可以存放多种数据类型,取值要强制转换即拆箱
Array的优点:
Array可以是多维的,但是ArrayList始终是一维的
Array的起始下标是可以设置,但是ArrayList的起始下标始终为零
其实有很多方法(均为非静态方法),但是没时间打字,以后有时间再打,或者说需要用的的时候再搜索
这里有个特别的方法:BinarySearch(属于非静态方法):使用二分检索算法再已排序的ArrayList或它的一部分中查找特定元素。
4.6 List类
List类是ArrayList的范型等效类
个人感觉像数据结构里的链表
- 可以创建自己的对象
eg!!!!!(之前,没注意这个好特别!!!)
struct Stud
{
public int sno;
public string sname;
};
class program
{
static void Main()
{
int i;
List < Stud > myset = new List<Stud>(); //定义集合myset
Stud s1 = new Stud();
s1.sno = 101;
s1.sname = "李明";
myset.Add(s1); //将一个结构体对象加入myset集合中
}
}