.net/dotnet:一般指.Net Framework框架.一种平台,一种技术

C#(sharp):一种编程语言,可以开发基于.net平台的应用

.net都能干什么?

  • 桌面应用程序 Winform
  • Internet应用程序 ASP.NET
  • 手机开发 wp8
  • Unity3D游戏开发或者虚拟现实

.NET俩种交互模式

  • C/S:客户机(Client)/服务器模式(Server) winform应用程序
  • B/S:浏览器(Browser)/服务器模式(Server) Internet应用程序

1.1 开发工具:Visual Studio

新建项目:选择Visual C#->Windows->控制台应用程序,起一个英文名称(最好见名知意)
一个解决方案下可以有多个项目:解决方案右键->添加->新建项目

.cs结尾的称为类文件

解决方案资源管理器(视图里找)

Program组成部分

  • 命名空间
  • 方法或函数(Main函数为程序的入口)

.sln: 解决方案文件,里面包含整个解决方案的信息,可以双击运行

.csproj: 项目文件,里面包含项目的信息,可以双击运行

1.2 C#基础

C#中,每行代码都以;结束.

输出: Console.WriteLine("输出内容");

Console.ReadKey(); 作用:暂停当前程序,等待用户按下任意键继续,按下的任意键将显示在控制台当中

vs快捷键:

  • Ctrl+K+D 快速对齐
  • Ctrl+S 保存
  • Ctrl+Z 撤销
  • Ctrl+J 提示
  • Ctrl+K+C 注释
  • Ctrl+K+U 取消注释
  • #region…#endregion 折叠代码

vs设置: 工具->选项(推荐将字体(环境->字体和颜色)改为Consolas)

启动项目设置: 解决方案右键->属性->启动项目改为当前选定内容

项目的加载与卸载: 右键需要修改的项目->移除/卸载(不可用,当需要时可以右键重新加载)

1.3 注释符

作用:
1.注销
2.解释

单行注释: //
多行注释: /* 注释内容 */
文档注释: /// 多用来解释类或者方法

1.4 变量

在计算机中存储数据

语法: 变量类型 变量名 = 值;

整数类型: int 只能存整数,不能存储小数

小数类型: double 既能存整数,也能存小数,小数点后位数 15 ~ 16位

字符类型不能为空,并且只能有一个 字符: char ch = 'a';

字符串类型可以存空,字符串: string name = "张三";

存钱: decimal money = 5000m; 后面需加上一个m

变量命名规则:

  • 必须以字母下划线或"@"符号开头,不能以数字开头
  • 后面可以跟任意字母、数字、下划线
  • 不能更C#关键字重复
  • 区分大小写
  • 同一变量名不允许重复定义
  • 变量命名必须有意义
  • Camel命名规则:除第一个单词第一个字母小写,其他每一个单词第一个字母大写(变量命名)
  • Pascal命名规则:每一个单词第一个字母大写(类或者方法命名)

变量必须先声明,再赋值,最后再使用

1.5 赋值运算符 =

意义: 表示把等号右边的值赋值给等号左边的变量

"+"号作用:
1.连接俩个字符串
2.相加(俩个数字)

占位符

使用方法: 先挖个坑,再填

多填:没效果
少填:抛异常

输出顺序:按照挖坑的顺序

保留小数:

{:0.00}//保留俩位小数

1
2
3
4
5
6
int n1 = 10;
int n2 = 20;
int n3 = 30;
//占位符
Console.WriteLine("第一个数字:{0},第二个数字:{1},第三个数字:{2}", n1, n2, n3);
Console.ReadKey();

交换变量

交换变量:
1.设置中间变量temp
2.交换俩整型变量:n1=n1-n2;n2=n1+n2;n1=n2-n1;

1.6 输入

string str = Console.ReadLine();

1.7转义符

转义符指的是一个’’+一个特殊字符组成一个具有特殊意义的字符

\n:表示换行
\":表示一个英文半角的双引号
\t:表示一个Tab键的空格
\b:表示退格键,放字符串俩边无用
@:
1.取消\转义作用
2.将字符串按照原格式输出
\r\n:windows操作系统不认识\n,只认识\r\n
\\:表示一个\

1.8 算术运算符 (二元运算符)

加(+)、减(-)、乘( * )、除(/)、取余(%)

1.9 显式类型转换和隐式类型转换

要求等号俩边参与运算的操作数的类型必须一致,如果不一致,满足下列条件会发生自动类型转换,或者称之为隐式类型转换

  • 俩种类型兼容
  • 目标类型大于原类型(eg:double>int) int — double

强制类型转换 double — int 显式类型转换 (eg:(int)double值)

  • 俩种类型相兼容
  • 大的转换为小的

语法: (待转换的类型)要转换的值

1.10 Convert类型转换

条件:

  • 面上必须要过得去
1
2
3
4
5
6
string s = "123";
double d = Convert.ToDouble(s);
int n = Convert.ToInt32(s);
Console.WriteLine(d);
Console.WriteLine(n);
Console.ReadKey();

1.11 加加减减 (一元运算符)

++: 分为前++、后++,最终结果都为变量+1,不同的是前++是先+1再用+1后的值去运算,后++是先用原先的值参与运算再将这个变量+1
–: 同上

一元运算符优先级高于二元运算符

1.12 关系运算符和逻辑运算符

关系运算符:
大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、等于(==)、不等于(!=)

bool类型:

  • True
  • False

逻辑运算符:
逻辑与(&&)全真才真,一假就假、逻辑或(||)全假才假,一真就真、逻辑非(!)

&&优先级高于||

1.13 复合赋值运算符

+=、-=、*=、/=、%=

异常捕获:
1
2
3
4
5
6
try
{
可能出异常的代码
}catch{
出异常执行代码
}

2 流程控制

循环结构:程序从Main函数进入,从上到下一行一行的执行,不会落下任意一行
分支结构:if if-else
选择结构:if else-if switch-case
循环结构:while do-while for foreach

2.1 if

if:
语法:
if(判断条件)
{
要执行的代码;
}

判断条件:一般为关系表达式或者bool类型的值

if-else:
语法:
if(判断条件)
{
条件成立执行的代码;
}else{
条件不成立执行代码;
}

if else-if:
语法:
if(判断条件1)
{
条件1成立执行的代码;
}else if(判断条件2)
{
条件2成立执行的代码;
}…
else{
条件都不成立执行代码;
}

2.2 switch-case

作用: 用于处理多条件的定值的判断

语法:
switch(变量或者表达式的值)
{
case 值1:要执行的代码;
break;
case 值2:要执行的代码;
break;
case 值3:要执行的代码;
break;

default:要执行的代码;
break;
}

案例: 判断年份

案例描述: 输入年份和月份,输出对应的天数

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using System;

namespace 判断闰年
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入一个年份");
try
{
int year = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("请输入一个月份");
try
{


int month = Convert.ToInt32(Console.ReadLine());//1~12
if (month >= 1 && month <= 12)
{
int day = 0;//声明一个变量用来存储天数
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day = 31;
break;
case 2:
//有平年和润年的不同
if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
{
day = 29;
}
else
{
day = 28;
}
break;
default://4,6,9,11
day = 30;
break;
}
Console.WriteLine("{0}年{1}月有{2}天", year, month, day);
}//if判断
else
{
Console.WriteLine("输入的月份不符合要求,程序退出");
}
}
catch//月份
{
Console.WriteLine("输入的月份有误,程序退出");
}
}
catch//年份
{
Console.WriteLine("输入的年份有误,程序退出");
}
Console.ReadKey();
}
}
}

2.3 while

语法:
while(循环条件)
{
循环体;
}

break用法:
1.跳出switch-case结构
2.跳出当前循环
一般不单独使用,而是跟着if判断一起使用

特点:先判断,再执行,有可以一遍循环都不执行

2.4 do-while循环

语法:
do
{
循环体;
}while(循环条件);

特点:先执行,再判断,至少执行一遍

断点调试
  • 设置断点(在行号前点击空白处)
  • 单步运行(F11逐语句调试)
  • 观察变量(鼠标放在变量名上观察)
  • F10逐过程调试

2.5 for循环

语法:
for(表达式1;表达式2;表达式3)
{
循环体4;
}

表达式1:一般为声明循环变量,记录循环的次数(int i = 0;)
表达式2:一般为循环条件
表达式3:一般为改变循环条件的代码,使循环条件终会不成立,否则就是死循环

顺序:1->2->4->3->2->4->3->…

代码提示: 输入for,再按俩下Tab键

案例: 水仙花数

案例描述:输出三位数的水仙花数(水仙花数:每位数字的三次方的和等于原数字)

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;

namespace 水仙花数
{
class Program
{
static void Main(string[] args)
{
for (int i = 100; i <= 999; i++)
{
int bai = i / 100;
int shi = i % 100 / 10;
int ge = i % 10;
if (bai*bai*bai+shi*shi*shi+ge*ge*ge==i)
{
Console.WriteLine("{0}\t", i);
}
}
Console.ReadKey();
}
}
}

2.6 for循环嵌套

案例: 九九乘法表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;

namespace 九九乘法表
{
class Program
{
static void Main(string[] args)
{
for (int i = 1; i <=9; i++)
{
for(int j=1;j<=i;j++)
{
Console.Write("{0}x{1}={2}\t", j, i, i * j);
}
Console.WriteLine();//换行
}
Console.ReadKey();
}
}
}

2.7 类型转换

int.TryParse:尝试将一个字符串转换成int类型

eg:

1
2
3
4
5
6
7
int number = 0;
//参数 返回值
bool b = int.TryParse("123",out number);
Console.WriteLine(b);
Console.WriteLine(number);
//转换成功:b = True number = 123
//转换失败:b = False number = 0
案例: 质数

案例描述:
找出100以内的所有质数(质数/素数:只能被1和本身整除的数字,比如:2)

提示:
continue用法:
结束本次循环,判断循环条件,如果成立则进入下一次循环,否则退出循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;

namespace 质数
{
class Program
{
static void Main(string[] args)//计算质数
{
for(int i=2;i<=100;i++)
{
bool b = true;
for(int j=2;j<i;j++)
{
if(i%j==0)
{
b = false;
break;
}
}
if(b)
{
Console.WriteLine(i);
}
}
Console.ReadKey();
}
}
}

2.8 三元表达式

语法: 表达式1?表达式2:表达式3;

表达式1一般为一个关系表达式
如果1为True,结果为2的值;如果1为False,结果为3的值
2与3与整个三元表达式类型须一致

案例: 随机数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

namespace 随机数
{
class Program
{
static void Main(string[] args)
{
while(true)
{
//产生随机数
//1.创建产生随机数的对象
Random r = new Random();
//2.让产生随机数的对象调用方法来产生随机数
int rNumber = r.Next(1, 11);//产生1~10的随机数
Console.WriteLine(rNumber);
Console.ReadKey();
}
}
}
}

3 复杂数据类型

3.1 常量

不能被重新赋值

语法: const 变量类型 变量名 = 值;

3.2 枚举

语法: [public] enum 枚举名 { 值1, 值2, 值3, ... }

public: 访问修饰符,公开的,哪都可以访问
enum: 声明枚举的关键字
枚举名: Pascal命名规范

枚举就是一个变量类型,只是枚举声明、赋值、使用的方式与普通变量类型不同

枚举类型和string、int类型之间转换:

  • 枚举类型与int类型是兼容的(枚举从0开始),可以使用强制类型转换相互转换
  • int类型转枚举:超出枚举范围直接输出int值
  • Enum.Parse(typeof(要转换的枚举类型即枚举名),“要转换的字符串”)字符串转换为枚举类型
    • 如果转换的字符串是数字且枚举中没有,不会抛异常
    • 如果转换的是文本且枚举中没有,会抛异常
  • 所有类型都可以转换为string类型 调用ToString()

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;

namespace 枚举
{
public enum Gender
{
男,

}
class Program
{
static void Main(string[] args)
{
//Enum.Parse(typeof(要转换的枚举类型),"要转换的字符串")转换为枚举类型
//所有类型都可以转换为string类型 调用ToString()
Gender gender = Gender.男;
Console.ReadKey();
}
}
}

3.3 结构

作用: 一次性声明多个不同类型的变量

语法: [public] struct 结构名 { 成员;//字段 }

字段可以存储多个值,规范上每个字段前加一个下划线_

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;

namespace 结构
{
public struct Person
{
public string _name;//字段
public int _age;
public Gender _gender;
}
public enum Gender
{
男,

}
class Program
{
static void Main(string[] args)
{
Person zsPerson;
zsPerson._name = "张三";
zsPerson._age = 11;
zsPerson._gender = Gender.男;
Console.WriteLine(zsPerson._name);
Console.WriteLine(zsPerson._age);
Console.WriteLine(zsPerson._gender);
}
}
}

3.4 数组

一次性存储多个相同类型的变量

语法: 数组类型[] 数组名=new 数组类型[数组长度];

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;

namespace 数组
{
class Program
{
static void Main(string[] args)
{
int[] nums = new int[10];
int[] numsTwo = { 1, 2,7, 4, 5 };
Array.Sort(numsTwo);//升序排列
Array.Reverse(numsTwo);//反转数组
for(int i=0;i<nums.Length;i++)
{
nums[i] = i;
}
for (int i = 0; i < nums.Length; i++)
{
Console.WriteLine(nums[i]);
}
Console.ReadKey();
}
}
}

冒泡排序

将数组中的元素从大到小或者从小到大进行排序

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;

namespace 冒泡排序
{
class Program
{
static void Main(string[] args)
{
int[] number = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
for (int i = 0; i < number.Length-1; i++)
{
for(int j=0;j<number.Length-i-1;j++)
{
if(number[j]>number[j+1])
{
int temp = number[j + 1];
number[j + 1] = number[j];
number[j] = temp;
}
}
}
for (int i = 0; i < number.Length; i++)
{
Console.WriteLine(number[i]);
}
Console.ReadKey();
}
}
}

3.5 方法(函数)

函数就是将一堆代码进行重用的一种机制

语法:
[public] static 返回值类型 方法名 ([参数列表]) { 方法体; }

static: 静态的
方法名: Pascal命名规则

方法写好后需在Main()函数中调用
调用语法:类名.方法名([参数]);

如果你写的方法跟Main()函数同在一个类(Program)中,类名可以省略

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace 方法
{
class Program
{
static void Main(string[] args)
{
int max=Program.GetMax(1, 3);
Console.WriteLine(max);
Console.ReadKey();
}
/// <summary>
/// 求俩个数最大值并返回
/// </summary>
/// <param name="n1">第一个整数</param>
/// <param name="n2">第二个整数</param>
/// <returns>最大值</returns>
public static int GetMax(int n1,int n2)
{
return n1 > n2 ? n1 : n1;
}
}
}

return作用:
1.在方法中返回要返回的函数值
2.立即结束本方法

调用者:Main()函数中调用其他方法;被调用者:其他方法

如果被调用者要使用调用者的值:

  • 传递参数
  • 使用静态字段来模拟全局变量 public static int _number = 10;(函数外,Program类中)

如果调用者要得到被调用者的值:

  • 返回值

不管是实参还是形参都是在内存中开辟了空间的

方法的功能一定是单一的,方法中最忌讳的就是出现提示用户输入的字眼

3.5.1 out参数

返回多个类型相同的值的时候,可以考虑返回一个数组
返回对个不同类型的值的时候,可以考虑使用out参数

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
//out 参数:可以返回多个不同的值
namespace out参数
{
class Program
{
static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] res = GetMaxMinSumAvg(numbers);
Console.WriteLine("最大值是{0},最小值是{1},总和是{2},平均值是{3}",res[0],res[1],res[2],res[3]);

int max;
int min;
int sum;
int avg;
bool b;
string s;
double d;
Test(numbers, out max, out min, out sum, out avg,out b,out s,out d);
Console.WriteLine(max);
Console.WriteLine(min);
Console.WriteLine(sum);
Console.WriteLine(avg);
Console.WriteLine(b);
Console.WriteLine(s);
Console.WriteLine(d);
Console.ReadKey();

}
/// <summary>
/// 求数组最大最小总和平均值
/// </summary>
/// <param name="nums">传入数据数组</param>
/// <returns>返回的数组</returns>
public static int[] GetMaxMinSumAvg(int[] nums)
{
int[] res = new int[4];
res[0] = nums[0];//max
res[1] = nums[0];//min
res[2] = 0;//sum
for(int i=0;i<nums.Length;i++)
{
if(nums[i]>res[0])
{
res[0] = nums[i];
}
if(nums[i]<res[1])
{
res[1] = nums[i];
}
res[2] += nums[i];
}
//平均值
res[3] = res[2] / nums.Length;
return res;
}
/// <summary>
/// 求数组最大最小总和平均值
/// </summary>
/// <param name="nums">传入数组</param>
/// <param name="max">多余返回的最大值</param>
/// <param name="min">多余返回的最小值</param>
/// <param name="sum">多余返回的总和</param>
/// <param name="avg">多余返回的平均值</param>
public static void Test(int[] nums, out int max, out int min, out int sum, out int avg, out bool b, out string s, out double d)
{
//out 参数要求在方法内给初值
max = nums[0];//max
min = nums[0];//min
sum = 0;//sum
for (int i = 0; i < nums.Length; i++)
{
if (nums[i] > max)
{
max = nums[i];
}
if (nums[i] < min)
{
min = nums[i];
}
sum += nums[i];
}
//平均值
avg = sum / nums.Length;
b = true;
s = "123";
d = 3.14;
}
}
}

3.5.2 ref参数

能够将一个变量带入一个方法中进行改变,改变完成后,再将改变后的值带出方法

要求:在方法外必须赋初值

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace ref参数
{
class Program
{
static void Main(string[] args)
{
double salary = 5000;
JiangJin(ref salary);
Console.WriteLine(salary);
Console.ReadKey();
}
public static void JiangJin(ref double s)
{
s += 500;
}
public static void FaKuan(double s)
{
s -= 500;
}
}
}
//5500

3.5.3 params可变参数

将实参列表中跟可变参数数组类型一致的元素都当做数组的元素去处理

params可变参数只能做最后一个参数且只能有一个

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;

namespace params参数//可变参数params 只能做成最后一个参数且只能有一个
{
class Program
{
static void Main(string[] args)
{
int[] score = { 98,78,90 };
Test("张三", 360,98, 78, 90);
Console.ReadKey();
}
public static void Test(string name, int id,params int[] score)
{
int sum = 0;
for(int i=0;i<score.Length;i++)
{
sum += score[i];
}
Console.WriteLine("{0}这次考试的总成绩是{1},学号为{2}", name, sum,id);
}
}
}
//张三这次考试的总成绩是266,学号为360

3.5.4 方法的重载

方法的重载指的是方法的名称相同、参数不同

  • 参数个数相同,类型就不能相同
  • 参数类型相同,个数就不能相同

3.5.5 方法的递归

递归:方法自己调用自己

案例: 飞行棋

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
using System;
//保留俩位小数(会四舍五入)
//double num=0.12453;
//string s=num.ToString("0.00");
//num=Convert.ToDouble(s);
namespace 飞行棋项目
{
class Program
{
public static int[] Maps = new int[100];//静态字段模拟全局变量
public static int[] PlayerPos = new int[2];//声明一个静态数组存储玩家坐标
public static string[] PlayerNames = new string[2];//存储玩家姓名
public static bool[] Flags = new bool[2];//Flags[0]=false,Flags[1]=false;
static void Main(string[] args)
{
GameShow();
#region 输入姓名
Console.WriteLine("请输入玩家A的姓名:");
PlayerNames[0] = Console.ReadLine();
while(PlayerNames[0]=="")
{
Console.WriteLine("玩家A的姓名不能为空");
PlayerNames[0] = Console.ReadLine();
}
Console.WriteLine("请输入玩家B的姓名:");
PlayerNames[1] = Console.ReadLine();
while (PlayerNames[1] == ""||PlayerNames[1]==PlayerNames[0])
{
if(PlayerNames[1]=="")
{
Console.WriteLine("玩家A的姓名不能为空");
PlayerNames[1] = Console.ReadLine();
}else
{
Console.WriteLine("玩家B的姓名不能跟A的相同,请重新输入");
PlayerNames[1] = Console.ReadLine();
}

}
#endregion
//玩家姓名输入完成后首先清屏
Console.Clear();
GameShow();
Console.WriteLine("{0}的士兵用A表示",PlayerNames[0]);
Console.WriteLine("{0}的士兵用B表示",PlayerNames[1]);
InitailMap();
DrawMap();

while(PlayerPos[0]<99&&PlayerPos[1]<99)
{
if(Flags[0]==false)
{
PlayGame(0);
}
else
{
Flags[0] = false;
}
if(PlayerPos[0]>=99)
{
Console.WriteLine("玩家{0}胜利",PlayerNames[0]);
break;
}
if (Flags[1] == false)
{
PlayGame(1);
}
else
{
Flags[1] = false;
}
if (PlayerPos[1] >= 99)
{
Console.WriteLine("玩家{0}胜利", PlayerNames[1]);
break;
}
}//while
Console.ReadKey();
}
/// <summary>
/// 游戏头
/// </summary>
public static void GameShow()
{
Console.ForegroundColor = ConsoleColor.Blue;//添加颜色
Console.WriteLine("************************");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("************************");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("*******飞行棋项目*******");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("************************");
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("************************");
}
/// <summary>
/// 初始化地图
/// </summary>
public static void InitailMap()
{
int[] luckyturn = { 6, 23, 40, 55, 69, 83 };//幸运圆盘◎
for(int i=0;i<luckyturn.Length;i++)
{
//int index = luckyturn[i];
Maps[luckyturn[i]] = 1;
}
int[] landMine = { 5, 13, 17, 33, 38, 50, 64, 80, 94 };//地雷☆
for (int i = 0; i < landMine.Length; i++)
{
Maps[landMine[i]] = 2;
}
int[] pause = { 9, 27, 60, 93 };//暂停▲
for (int i = 0; i < pause.Length; i++)
{
Maps[pause[i]] = 3;
}
int[] timeTunnel = { 20, 25, 45, 63, 72, 88, 90 };//时空隧道卐
for (int i = 0; i < timeTunnel.Length; i++)
{
Maps[timeTunnel[i]] = 4;
}
}

/// <summary>
/// 画地图
/// </summary>
public static void DrawMap()
{
Console.WriteLine("图例:幸运圆盘:◎ 地雷:☆ 暂停:▲ 时空隧道:卐 ");
#region 第一横行
for (int i=0;i<30;i++)
{
Console.Write(DrawStringMap(i));
}//for
#endregion
//画完第一行需换行
Console.WriteLine();
#region 第一竖行
for (int i=30;i<35;i++)
{
for(int j=0;j<=28;j++)
{
Console.Write(" ");
}
Console.Write(DrawStringMap(i));
Console.WriteLine();
}
#endregion

#region 第二横行
for(int i=64;i>=35;i--)
{
Console.Write(DrawStringMap(i));
}
#endregion
Console.WriteLine();
#region 第二竖行
for (int i=65;i<=69;i++)
{
Console.WriteLine(DrawStringMap(i));
}
#endregion

#region 第三横行
for(int i=70;i<=99;i++)
{
Console.Write(DrawStringMap(i));
}
#endregion
Console.WriteLine();
}//DrawMap
/// <summary>
/// 从画地图方法中抽象出来的一个方法
/// </summary>
/// <param name="i">位置坐标</param>
/// <returns></returns>
public static string DrawStringMap(int i)
{
string str="";
#region 画图
if (PlayerPos[0] == PlayerPos[1] && PlayerPos[1] == i)
{
str="<>";//玩家坐标相同并且都在地图上
}
else if (PlayerPos[0] == i)
{
str="A";//shift+空格 切全角
}
else if (PlayerPos[1] == i)
{
str="B";//shift+空格 切全角
}
else
{
switch (Maps[i])
{
case 0:
Console.ForegroundColor = ConsoleColor.Yellow;
str = "□";
break;
case 1:
Console.ForegroundColor = ConsoleColor.Red;
str = "◎";
break;
case 2:
Console.ForegroundColor = ConsoleColor.Cyan;
str = "☆";
break;
case 3:
Console.ForegroundColor = ConsoleColor.Green;
str = "▲";
break;
case 4:
Console.ForegroundColor = ConsoleColor.Blue;
str="卐";
break;
}//switch
}//else
return str;
#endregion
}

/// <summary>
/// 玩游戏
/// </summary>
public static void PlayGame(int playerNumber)
{
Random r = new Random();
int rNumber = r.Next(1, 7);
Console.WriteLine("{0}按任意键开始掷骰子", PlayerNames[playerNumber]);
Console.ReadKey(true);
Console.WriteLine("{0}掷出了{1}", PlayerNames[playerNumber],rNumber);
PlayerPos[playerNumber] += rNumber;
ChangePos();
Console.ReadKey(true);
Console.WriteLine("{0}按任意键继续行动", PlayerNames[playerNumber]);
Console.ReadKey(true);
Console.WriteLine("{0}行动完了", PlayerNames[playerNumber]);
Console.ReadKey(true);
if (PlayerPos[playerNumber] == PlayerPos[1- playerNumber])
{
Console.WriteLine("玩家{0}踩到玩家{1},玩家{2}退6格", PlayerNames[playerNumber], PlayerNames[1- playerNumber], PlayerNames[1- playerNumber]);
PlayerPos[1- playerNumber] -= 6;
ChangePos();
Console.ReadKey(true);
}
else//关卡
{
//玩家坐标
switch (Maps[PlayerPos[playerNumber]])//0 1 2 3 4
{
case 0:
Console.WriteLine("玩家{0}踩到了方块,安全", PlayerNames[playerNumber]);
Console.ReadKey(true);
break;
case 1:
Console.WriteLine("玩家{0}踩到了幸运圆盘,请选择:1--交换位置,2--轰炸对方", PlayerNames[playerNumber]);
string input = Console.ReadLine();
while (true)
{
if (input == "1")
{
Console.WriteLine("玩家{0}与玩家{1}交换位置", PlayerNames[playerNumber], PlayerNames[1- playerNumber]);
Console.ReadKey(true);
int temp = PlayerPos[playerNumber];
PlayerPos[playerNumber] = PlayerPos[1- playerNumber];
PlayerPos[1- playerNumber] = temp;
Console.WriteLine("交换完成,按任意键继续!!!");
Console.ReadKey(true);
break;
}
else if (input == "2")
{
Console.WriteLine("玩家{0}轰炸玩家{1},玩家{2}退6格", PlayerNames[playerNumber], PlayerNames[1- playerNumber], PlayerNames[1- playerNumber]);
Console.ReadKey(true);
PlayerPos[1- playerNumber] -= 6;
ChangePos();
Console.WriteLine("玩家{0}退了6格", PlayerNames[1- playerNumber]);
Console.ReadKey(true);
break;
}
else
{
Console.WriteLine("只能输入1或者2 :1--交换位置,2--轰炸对方");
input = Console.ReadLine();
}
}
break;
case 2:
Console.WriteLine("玩家{0}踩到了地雷,退6格", PlayerNames[playerNumber]);
Console.ReadKey(true);
PlayerPos[playerNumber] -= 6;
ChangePos();
break;
case 3:
Console.WriteLine("玩家{0}踩到了暂停,暂停一回合", PlayerNames[playerNumber]);
Flags[playerNumber] = true;
Console.ReadKey(true);
break;
case 4:
Console.WriteLine("玩家{0}踩到了时空隧道,前进10格", PlayerNames[playerNumber]);
PlayerPos[playerNumber] += 10;
ChangePos();
Console.ReadKey(true);
break;
}//switch
}//else
ChangePos();
Console.Clear();
DrawMap();
}

/// <summary>
/// 玩家坐标发生改变时调用
/// </summary>
public static void ChangePos()
{
if (PlayerPos[0]<0)
{
PlayerPos[0] = 0;
}
if (PlayerPos[0] >99)
{
PlayerPos[0] = 99;
}
if (PlayerPos[1] < 0)
{
PlayerPos[1] = 0;
}
if (PlayerPos[1] > 99)
{
PlayerPos[1] = 99;
}
}
/// <summary>
/// 反转数组内容
/// </summary>
/// <param name="names">传入数组</param>
public static void Test(string[] names)
{
for (int i = 0; i < names.Length / 2; i++)
{
string temp = names[i];
names[i] = names[names.Length - 1 - i];
names[names.Length - 1 - i] = temp;
}
}

}
}

4 面向对象

面向对象意在写出一个通用的代码屏蔽差异

描述一个对象通常描述这个对象的属性和方法

类:将具有相同属性和方法的对象进一步封装,抽象出类的概念

对象是根据类创建出来的

4.1 类

语法:
[public] class 类名 { 字段(Fiels); 属性(Property); 方法(Method); }

添加类:需要添加类的项目->右键->添加->类(.cs)

写好一个类之后,我们需要创建这个类的对象,我们称创建类的过程称为类的实例化,使用关键字new

类不占内存,对象占内存

属性的作用就是保护字段、对字段的赋值和取值进行限定。
属性的本质就是get(读)和set(写)俩个方法

访问修饰符:

  • public:公开的,在哪都能访问
  • private:私有的,只能在当前类的内部进行访问,出了这个类就访问不到

静态与非静态的区别:
1.在非静态类中,既可以有实例成员,也可以有静态成员
2.在调用实例成员时,需要使用对象名.实例成员
在调用静态成员时,需要使用类名.静态成员名

总结:

  • 静态成员必须使用类名区调用,而实例成员使用对象名区调用
  • 静态函数中,只能访问静态成员,不允许访问实例成员
  • 实例函数中,既可以访问静态成员,也可以访问实例成员
  • 静态类中只允许有静态成员,不允许出现实例成员

使用:
1.如果你需要将你的类当做一个工具类使用时可以考虑将类写成静态的
2.静态类在整个项目中资源共享
只有在程序全部结束后静态类才会释放资源

堆、栈 静态存储区域

释放资源:GC

构造函数:
创建对象时会执行构造函数
构造函数可以有重载
作用:帮助我们初始化对象
构造函数是一个特殊的方法:
1.没有返回值,连void也不用写
2.名称必须跟类名一样

类中有一个默认的无参数的构造函数,当你写了一个新的构造函数会替代原先的构造函数

new关键字帮我们干的3件事:
1.在内存中开辟一块空间
2.在开辟的空间中创建对象
3.调用对象的构造函数进行初始化对象

this关键字:
1.代表当前类的对象
2.在类中显示调用本类的构造函数 :this

析构函数:
当程序结束时,析构函数才执行
作用:帮助我们释放资源

Person.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 面向对象初级
{
public class Person//工具类使用静态类,静态类在整个项目中资源共享
{
//析构函数
~Person()
{
Console.WriteLine("析构函数调用");//帮助我们释放资源
}
public Person(string name,int age,char gender)
{
this._name = name;
this._age = age;
this._gender = gender;
Console.WriteLine("构造函数");
}
public Person(string name, int age):this(name,age,'男')//this:在类中显示调用本类的构造函数 优点:减少代码重复量
{
//this._name = name;
//this._age = age;
}
public Person(string name)
{
this._name = name;
}
private string _name;
//属性 保护字段
public string Name
{
get { return _name; }
set { _name = value; }
}
private int _age;
public int Age
{
get{ return _age; }
set {
if(value<0||value>100)
{
value = 0;
}
_age = value; }
}

char _gender;
public char Gender
{
get {
if(_gender!='男'&&_gender!='女')
{
return _gender = '男';
}
return _gender; }
set { _gender = value; }
}


public void CHLSS()
{
Console.WriteLine("{0},{1}岁,{2},会吃喝拉撒睡",this.Name,this.Age,this.Gender);
}
}
}

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;

namespace 面向对象初级
{
class Program
{
static void Main(string[] args)
{
//创建类的对象 -> 类的实例化
//类不占内存,对象占内存
Person sunQuan = new Person("孙权",18,'男');
sunQuan.CHLSS();
Console.ReadKey();
}
}
}
//构造函数
//孙权,18岁,男,会吃喝拉撒睡

4.2 命名空间

导入类所在命名空间:
1.用鼠标点
2.alt+shift+F10
3.记住常见类的命名空间,手敲

一个项目中引用另一个项目的类
1.添加引用:引用->右键->引用
2.引用命名空间 using 命名空间;

4.3 值类型和引用类型

区别:
1.在内存上存储的地方不一样
2.在传递值类型和传递引用类型时,传递的方式不同(值传递和引用传递)

值传递:int、double、bool、char、decimal、struct、enum
引用传递:string、自定义类、数组

存储:
值类型的值是存储在内存的栈当中
引用类型的值是存储在内存的堆中

4.4 字符串

1.字符串的不可变性(当重新给一个字符串赋值后,原来值并没用销毁,而是重新开辟一块内存存储新值)
当程序结束后,GC扫描整个内存,如果发现有的空间没有被指向,立即将它销毁

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
//字符串的不可变性
string s1 = "张三";
string s2 = "张三";
Console.ReadKey();
}
}
}

2.可以将字符串看成是char类型的只读数组,可以通过下标访问字符串中的一个元素

  • 将字符串转换为char类型数组 字符串.ToCharArray()
  • 将字符数组转换为字符串 new string(字符数组)

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
//可以将字符串看成是char类型的只读数组
string s = "abcdef";
Console.WriteLine(s[0]);
//s[0] = 'b';不能这样做
//首先将字符串转换为char类型数组
char[] chs = s.ToCharArray();
chs[0] = 'b';
//将字符数组转换为字符串
s = new string(chs);
Console.WriteLine(s[0]);
Console.WriteLine(s);
Console.ReadKey();
}
}
}
//b
//bbcdef

StringBuilder:不开内存空间,比string快
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();//同一块内存
string str = null;
//创建计时器,用来记录程序运行的时间
Stopwatch sw = new Stopwatch();
sw.Start();//开始计时
for(int i=0;i<100000;i++)
{
//str += i;
sb.Append(i);
}
sw.Stop();//结束计时
Console.WriteLine(sb.ToString());
Console.WriteLine(sw.Elapsed);
Console.ReadKey();
}
}
}

s.ToUpper() 转换为大写
s.ToLower() 转换为小写
s1.Equals(s1,StringComparison.OrdinalIgnoreCase) 比较 StringComparison.OrdinalIgnoreCase:忽略比较字符串大小写

**分割字符串:**s.Split(chs,StringSplitOptions.RemoveEmptyEntries) chs:需要移除的字符数组 StringSplitOptions.RemoveEmptyEntries:去除空项
返回字符串类型数组

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
//字符串分割Split()返回字符串类型数组
string s = "a b dfd _+ = ,,, fdf";
char[] chs = { ' ', '_', '+', '=', ',' };
string[] str = s.Split(chs,StringSplitOptions.RemoveEmptyEntries);
Console.ReadKey();
}
}
}

s1.Contains(s2) s1包含s2
s.Replace(要替换的内容,替换成为的内容) 替换

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string str = "国家关键人物老赵";
if(str.Contains("老赵"))
{
str = str.Replace("老赵", "**");
}
Console.WriteLine(str);
Console.ReadKey();
}
}
}

s.SubString(起始位置0开始,截取个数) 截取字符串

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
//SubString 截取字符串
string str = "今天天气好晴朗,处处好风光";
str = str.Substring(1,2);
Console.WriteLine(str);
Console.ReadKey();
}
}
}
//天天

s.StartsWith(str) 以什么开始,返回bool类型
s.EndsWith(str) 以什么结尾,返回bool类型

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string str = "今天天气好晴朗,处处好风光";
if(str.StartsWith("今天"))
{
Console.WriteLine("是");
}
else
{
Console.WriteLine("不是");
}
Console.ReadKey();
}
}
}

str.IndexOf(字符串,开始查找位置包括当前位置); 判读该字符串第一次出现位置,从0开始
str.LastIndexOf(字符串,开始查找位置包括当前位置); 判断该字符串最后出现位置,从0开始

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string str = "今天天气好晴朗,处处好风光";
int index = str.IndexOf('天',2);
int index1 = str.LastIndexOf('天',2);
Console.WriteLine(index);
Console.WriteLine(index1);
Console.ReadKey();
}
}
}

str.Trim(); 去空格 返回string类型
str.TrimStart(); 去前面空格 返回string类型
str.TrimEnd(); 去后面空格 返回string类型

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string str = " hahaha ";
//str = str.Trim();
//str = str.TrimStart();
str = str.TrimEnd();
Console.Write(str);
Console.ReadKey();
}
}
}

string.IsNullOrEmpty(str) 判断字符串是否为NULL或Empty

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string str = null;
if(string.IsNullOrEmpty(str))
{
Console.WriteLine("是的");
}
else
{
Console.WriteLine("不是");
}
Console.ReadKey();
}
}
}

string.Join(字符串, 可变数组); 将数组按照指定的字符串连接,返回一个字符串

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string[] names = { "张三", "李四", "王五", "赵六" };
string strNew = string.Join("|", names);
Console.WriteLine(strNew);
Console.ReadKey();
}
}
}
案例: 字符串使用

案例描述:
文本文件中存储了多个文章标题、作者,
标题和作者之间用若干空格(数量不定)隔开,每行一个,
标题有的长有的短,输出到控制台的时候最多标题长度10.
如果超过10,则截取长度8的子串并且最后添加“…”,加一个竖线后输出作者的名字。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace 字符串
{
class Program
{
static void Main(string[] args)
{
string path = @"文件路径";
string[] contents = File.ReadAllLines(path, Encoding.Default);
for(int i=0;i<contents.Length;i++)
{
string[] strNew = contents[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine((strNew[0].Length > 10 ? strNew[0].Substring(0, 8)+"......r": strNew[0]) + "|" + strNew[1]);
}
Console.ReadKey();
}
}
}

4.5 继承

子类 派生类
父类 基类
子类继承了父类,继承了父类的属性和方法,但是子类没有继承父类的私有字段

继承的特性:
1.单根性:一个子类只能有一个父类
2.传递性

子类并没有继承父类的构造函数,但是子类会默认调用父类无参数的构造函数创建父类对象,让子类可以使用父类中的成员。所以,如果在父类中重新写了一个有参数的构造函数后,那个无参数的就被干掉了,子类就调用不到了,所以子类会报错。
解决方法:
1.在父类中重新写一个无参数的构造函数
2.在子类中显示的调用父类的构造函数,使用关键字:base()

object是所有类的基类

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System;

namespace 继承
{
class Program
{
static void Main(string[] args)
{
Reporter rep = new Reporter("狗仔", 34,'男',"偷拍");
rep.ReporterSayHello();
Programmer pro = new Programmer("程序猿", 23, '男', 3);
pro.ProgrammerSayHello();
Console.ReadKey();
}
}
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
private char _gender;
public char Gender
{
get { return _gender; }
set { _gender = value; }
}
public Person(string name, int age,char gender)
{
this.Name = name;
this.Age = age;
this.Gender = gender;
}
public void SayHello()
{
Console.WriteLine("大家好,我是人类");
}
}
public class Reporter : Person
{
public Reporter(string name,int age,char gender,string hobby)
:base(name,age,gender)
{
this.Hobby = hobby;
}
private string _hobby;
public string Hobby
{
get { return _hobby; }
set { _hobby = value; }
}

public void ReporterSayHello()
{
Console.WriteLine("我叫{0},我是一名记者,我的爱好是{1},我是{2}生,我今年{3}岁", this.Name, this.Hobby, this.Gender, this.Age);
}
public new void SayHello()
{
Console.WriteLine("大家好,我是记者");
}
}
public class Programmer : Person
{
public Programmer(string name, int age, char gender, int workYear)
: base(name, age, gender)
{
this.WorkYear = workYear;
}
private int _workYear;
public int WorkYear
{
get { return _workYear; }
set { _workYear = value; }
}

public void ProgrammerSayHello()
{
Console.WriteLine("我叫{0},我是一名程序员,我是{1}生,我今年{2}岁,我的工作年限是{3}年", this.Name, this.Gender, this.Age,this.WorkYear);
}
public new void SayHello()//new :隐藏从父类那里继承来的成员
{
Console.WriteLine("大家好,我是程序猿");
}
}
}

new关键字:
1.创建对象
2.隐藏从父类继承过来的同名成员 隐藏后果:子类调用不到父类的成员

4.6 里氏转换

1.子类可以赋值给父类 如果有一个地方需要父类作为参数,我们可以给一个子类代替
2.如果父类中装的是子类对象,那么可以将这个父类强转为子类对象

子类对象可以调用父类的成员,但是父类对象只能调用自己的成员

is: 表示类型转换,如果能转换成功,则返回true,不能转换成功返回false
as: 表示类型转换,如果能够转换则返回对应的对象,否则返回一个NULL

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;

namespace 里氏转换
{
class Program
{
static void Main(string[] args)
{
//1.子类可以赋值给父类:如果有一个地方需要父类作为参数,我们可以给一个子类代替
//Student s = new Student();
//Person p = s;
Person p = new Student();
//2.如果父类中装的是子类对象,那么可以将这个父类强转为子类对象
//is用法
//if(p is Student)
//{
// Student ss = (Student)p;
// ss.StudentSayHello();
//}
//else
//{
// Console.WriteLine("转换失败");
//}
//as用法
Student t = p as Student;
t.StudentSayHello();
Console.ReadKey();
}
}
public class Person
{
public void PersonSayHello()
{
Console.WriteLine("我是父类");
}
}
public class Student:Person
{
public void StudentSayHello()
{
Console.WriteLine("我是学生");
}
}
public class Teacher : Person
{
public void TeacherSayHello()
{
Console.WriteLine("我是老师");
}
}
}
protected

受保护的:可以在当前类的内部以及该类的子类中访问

4.7 ArrayList集合

集合好处(相对于数组):
1.长度可以任意改变
2.类型随意

我们将一个对象输出到控制台,默认情况下就是打印这个对象的命名空间

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System;
using System.Collections;

namespace ArrayList集合
{
class Program
{
static void Main(string[] args)
{
ArrayList list = new ArrayList();
list.Add(1);
list.Add(3.14);
list.Add(true);
list.Add("张三");
list.Add('男');
list.Add(5000m);
list.Add(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
Person p = new Person();
list.Add(p);
list.Add(list);
list.Remove(true);//删除单个元素
list.RemoveAt(0);//根据下标删除元素
for(int i=0;i<list.Count;i++)
{
if(list[i] is Person)
{
((Person)list[i]).SayHello();
}else if(list[i] is int[])
{
for(int j=0;j<((int[])list[i]).Length;j++)
{
Console.WriteLine(((int[])list[i])[j]);
}
}
else
{
Console.WriteLine(list[i]);
}
}


list.Clear();//清除所有元素
//添加集合元素 AddRange()
list.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
list.AddRange(list);
list.RemoveRange(0, 8);//根据下标删除范围元素
list.Sort();//升序排列
list.Reverse();//反转
list.Insert(1, 9);//在位置1插入数字9 InsertRange()在指定位置插入一个集合
bool b = list.Contains(1);//判断是否包含指定的内容
for(int i=0;i<list.Count;i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine(b);
Console.WriteLine(list.Count);
Console.WriteLine(list.Capacity);
Console.ReadKey();

}
}
public class Person
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
}

ArrayList集合长度:

  • count 表示这个集合中实际包含的元素个数 没元素:0
  • capcity 表示这个集合中可以包含的元素个数 没元素:0
    当实际包含的元素个数(count)超过了可以包含的元素个数(capcity)时,集合就会向内存中申请多开一倍的空间来保证集合的长度一直够用

4.8 HashTable集合 (键值对集合)

类似于生活中的字典,键值对对象[键]=值

键值对集合中,键必须是唯一的,值可以是重复的

使用foreach循环输出,不能使用for循环 var:根据值能够推断出来类型

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hashtable集合
{
class Program
{
static void Main(string[] args)
{
//var:根据值能够推断出来类型
//var n = 5;
//Console.WriteLine(n.GetType());
//创建一个键值对集合对象
Hashtable ht = new Hashtable();
ht.Add(1,"张三");
ht.Add(2, true);
ht.Add(3, '男');
ht.Add(false, "错误的");
//ht.Clear();//清空
ht[5] = "new";
ht[1] = "换掉张三";
//ht.Remove(5);
//Console.WriteLine(ht[1]);
//不能使用for循环遍历,使用foreach循环
foreach (var item in ht.Keys)
{
Console.WriteLine("键是---{0},值是---{1}",item,ht[item]);
}
//for (int i=0;i<ht.Count,;i++)
//{
// Console.WriteLine(ht[i]);
//}
Console.ReadKey();
}
}
}

4.9 Path类

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.IO;

namespace Path
{
class Program
{
static void Main(string[] args)
{
string str = @"文件路径";
//int index = str.LastIndexOf("\\");
//str = str.Substring(index + 1);
//Console.WriteLine(str);
//快速获得一个路径下文件的名字
Console.WriteLine(Path.GetFileName(str));
//获得没有扩展名的文件名
Console.WriteLine(Path.GetFileNameWithoutExtension(str));
//获得文件扩展名
Console.WriteLine(Path.GetExtension(str));
//获得文件所在文件夹名称
Console.WriteLine(Path.GetDirectoryName(str));
//获得文件全路径
Console.WriteLine(Path.GetFullPath(str));
//连接俩个字符串作为路径
Console.WriteLine(Path.Combine(@"c:\a\","b.txt"));
Console.ReadKey();
}
}
}

4.10 File类

File.Exists():判断是否存在
File.Copy():复制文件
File.Move():剪切,俩个参数,第一个原地址,第二个新地址
File.Delete():删除

读取文件的三个方法:

1.byte[] buffer = File.ReadAllBytes(@"文件路径"); string str = System.Text.Encoding.Default.GetString(buffer);//将二进制转换为字符串

2.string[] str = File.ReadAllLines(@"文件路径",Encoding.Default);//读取所有行

3.string str = File.ReadAllText(@"文件路径",Encoding.Default);

写入文件:

1.byte[] buffer = System.Text.Encoding.Default.GetBytes(str);//将字符串转换为字节数组 File.WriteAllBytes(@"文件路径",buffer);

2.File.WriteAllLines(@"文件路径",str数组);

3.File.WriteAllText(@"文件路径",str);

File.AppendAllText(@“文件路径”,str);//追加文字

多媒体(只能以字节形式)的复制:
byte[] buffer = File.ReadAllBytes(@"文件路径"); File.WriteAllBytes(@"存放路径",buffer);

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.IO;

namespace File
{
class Program
{
static void Main(string[] args)
{
//创建一个文件
//File.Create(@"F:\new.txt");
//Console.WriteLine("创建成功");
//Console.ReadKey();
//删除一个文件
//File.Delete(@"F:\str.docx");
//Console.WriteLine("删除成功");
//Console.ReadKey();
//赋值一个文件
File.Copy(@"F:\new.txt", @"F:\copy.txt");
Console.WriteLine("复制成功");
Console.ReadKey();
}
}
}

编码:

ASC 128
ASCII 256

GB2312 简体字(中国)
Big5 繁体字

unicode 全,但解析慢
UTF-8 web

将字符串以怎样的形式保存为二进制

乱码:
产生原因:保存文件的编码和打开文件的编码格式不同

Directory操作

Directory.CreateDirectory():创建文件夹
Directory.Delete(@“文件夹路径”,true):删除文件夹 true表示即使该文件夹下不为空也删除
Directory.Exists():判断文件夹是否存在
Directory.Move():剪切
Directory.GetDirectories():得到该路径下所有文件夹路径的字符串数组
Directory.GetFiles():得到该路径下所有文件路径的字符串数组 第二个参数为指定文件后缀名 *.avi

FileStream

操作字节

File只能操作小文件;操作大文件(字符):StreamReader、StreamWriter

读:

1
2
3
4
5
6
7
8
9
10
//创建FileStream对象
FileStream fsRead = new FileStream(@"文件路径",FileMode.Open,FileAccess.Read);
//创建缓冲区的大小
byte[] buffer = new byte[fsRead.Length];
//开始读取数据 返回的是这次实际读取到的数据
int r = fsRead.Read(buffer,0,buffer.Length);
//将字节数组转换为字符串
string str = System.Text.Encoding.Default.GetString(buffer);
fsRead.Close();//关闭流
fsRead.Dispose();//释放流占用的资源

写: 追加:FileMode.Append

1
2
3
4
using(FileStream fsWrite = new FileStream(@"文件路径",FileMode.OpenOrCreate,FileAccess.Write)){
byte[] buffer = System.Text.Encoding.Default.GetBytes(str);
fsWrite.Write(buffer,0,buffer.Length);
}

多媒体文件的复制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void CopyFile(string source,string target)
{
using(FileStream fsRead = new FileStream(source,FileMode.Open,FileAccess.Read)){
using(FileStream fsWrite = new FileStream(target,FileMode.OpenOrCreate,FileAccess.Write)){
//创建缓冲区的大小
byte[] buffer = new byte[1024*1024*7];
//开始读取数据 返回的是这次实际读取到的数据
while(true)
{
int r = fsRead.Read(buffer,0,buffer.Length);
if(r==0)//读完了
{
return;
}else{
fsWrite.Write(buffer,0,r);
}
}
}
}
}
//source:原文件路径
//target:复制到的文件路径

StreamReader读数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//使用FileStream来读取数据
using(FileStream fsRead = new FileStream(@"文件路径",FileMode.Open,FileAccess.Read)){
using(StreamReader sr = new StreamReader(fsRead,Encoding.Default)){
while(!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
}
}
Console.ReadKey();

//可简写为:

using(StreamReader sr = new StreamReader(@"文件路径"),Encoding.Default){
while(!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
}
Console.ReadKey();

StreamReader写数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//使用FileStream来写数据 追加:FileMode.Append
using(FileStream fsWrite = new FileStream(@"文件路径",FileMode.OpenOrCreate,FileAccess.Write)){
using(StreamWriter sw = new StreamWriter(fsWrite,Encoding.Default)){
sw.Write("xxx");//俩个字符替换一个字
}
}
Console.ReadKey();

//可简写为: true:追加

using(StreamWriter sw = new StreamWriter(@"文件路径"),true){
sw.Write("xxx");
}
Console.ReadKey();

4.11 List泛型集合

方法跟ArrayList差不多

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Collections.Generic;

namespace List泛型集合
{
class Program
{
static void Main(string[] args)
{
//创建泛型集合对象
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.AddRange(new int[] { 1, 2, 3, 4, 5, 6 });
list.AddRange(list);
//list泛型集合可以转换为数组
int[] nums = list.ToArray();
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
Console.ReadKey();
}
}
}

4.12 装箱和拆箱

装箱:就是将值类型转换为引用类型
拆箱:就是将引用类型转换为值类型

1
2
3
int n=10;
object o=n;//装箱
int nn=(int)o;//拆箱

装箱会浪费时间,代码中应该避免装箱和拆箱

注意:Convert.ToInt(str)没有发生任意类型的装箱和拆箱

发生装箱和拆箱的条件:看是否有继承关系,有继承关系才有可能发生

4.13 Dictionary集合

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections.Generic;

namespace Dictionary集合
{
class Program
{
static void Main(string[] args)
{
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "张三");
dic.Add(2, "李四");
dic.Add(3, "王五");
dic[1] = "新来的";
//遍历方式
//1.foreach
//foreach (var item in dic.Keys)
//{
// Console.WriteLine("{0}---{1}", item, dic[item]);
//}
//2.一对数据的遍历
foreach (KeyValuePair<int,string> kv in dic)
{
Console.WriteLine("{0}---{1}", kv.Key, kv.Value);
}
Console.ReadKey();
}
}
}

4.14 多态

多态:
概念:让一个对象能够表现出多种状态(类型)
实现多态的3种手段:
1.虚方法

将父类方法标记为虚方法,在其返回类型之前加virtual,这个函数子类要重写一遍,在重写方法返回类型前加override

2.抽象类

当父类中的方法不知道如何去实现时,可以考虑将父类写成抽象类abstract class,将方法写成抽象方法abstract 返回类型 子类也需要重写(在重写方法返回类型前加override),而且子类必须要实现父类中所有的抽象成员
实现多态:不能创建父类对象,可以创建子类对象Father f = new Son(); a.Eat();

抽象方法不能有方法体public abstract void func();
空实现:public abstract void func(){}

抽象类可以有非抽象成员,但是非抽象类中不能有抽象成员

如果子类也是抽象类,不用重写父类抽象成员

抽象类是由构造函数的,虽然不能被实例化

子类重写父类抽象函数时返回值和参数必须一样

如果父类中的方法有默认的实现,并且父类需要被实例化,这时可以考虑将父类定义成一个普通类,用虚方法来实现多态
如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将父类定义为抽象类

抽象类也可以有虚方法,子类也不是必须要重写虚方法

案例:使用多态求矩形的面积和周长以及圆形的面积和周长

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using System;

namespace 抽象类
{
class Program
{
static void Main(string[] args)
{
Shape shape = new Circle(5);
double area = shape.GetArea();
double perimeter = shape.GetPerimeter();
Console.WriteLine("面积:{0},周长:{1}", area, perimeter);
Console.ReadKey();
}
}
public abstract class Shape
{
public abstract double GetArea();
public abstract double GetPerimeter();
}
public class Circle : Shape
{
private double _r;
public double R
{
get { return _r; }
set { _r = value; }
}
public Circle(double r)
{
this.R = r;
}
public override double GetArea()
{
return Math.PI * this.R * this.R;
}

public override double GetPerimeter()
{
return 2 * Math.PI * this.R;
}
}

public class Square : Shape
{
private double _Height;

public double Height
{
get { return _Height; }
set { _Height = value; }
}
private double _Width;
public double Width
{
get { return _Width; }
set { _Width = value; }
}

public Square(double height,double width)
{
this.Height = height;
this.Width = width;
}

public override double GetArea()
{
return this.Height * this.Width;
}

public override double GetPerimeter()
{
return 2 * (this.Height + this.Width);
}
}
}

3.接口

接口就是一个规范、能力

语法:
[public] interface I...able { 成员; }

接口中的成员不允许添加访问修饰符
不允许写具有方法体的函数 自动属性
不能写字段和构造函数,只能有方法、属性、索引器、事件
一个类继承了一个接口就必须实现这个接口中所有成员
为了多态,接口不能被实例化,接口不能创建对象
接口中的成员不能有任何实现
接口与接口间可以继承,并且可以多继承
接口只能继承接口
类继承类A,继承接口B,写法上A在B前(先继承类)

显式实现接口就是为了解决方法重名问题

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;

namespace 显式实现接口
{
class Program
{
static void Main(string[] args)
{
//显式实现接口就是为了解决方法重名问题
IFlyable fly = new Bird();
fly.Fly();
Bird bird = new Bird();
bird.Fly();
Console.ReadKey();
}
}
public class Bird:IFlyable
{
public void Fly()
{
Console.WriteLine("鸟会飞");
}
/// <summary>
/// 显式实现接口
/// </summary>
void IFlyable.Fly()
{
Console.WriteLine("我是接口的Fly");
}
}
public interface IFlyable
{
void Fly();
}
}
访问修饰符

public:公开的,公共的
private:私有的,只有在当前类的内部访问
protected:受保护的,只能在当前类的内部以及该类的子类中访问
internal:只能在当前项目中访问,在同一个项目中,与public权限一样
protected internal:protected+internal

1.能够修饰类的修饰符:public、internal(默认)
2.可访问性不一致
子类访问权限不能高于父类访问权限,因为子类会暴露父类成员

简单工厂设计模式

设计模式:设计这个项目的一种方式

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;

namespace 简单工厂设计模式
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入你想要的笔记本品牌:");
string brand = Console.ReadLine();
NoteBook nb = GetNoteBook(brand);
nb.SayHello();
Console.ReadKey();
}
/// <summary>
/// 简单工厂的核心,根据用户的输入创建对象赋值给父类
/// </summary>
/// <param name="brand"></param>
/// <returns></returns>
public static NoteBook GetNoteBook(string brand)
{
NoteBook nb = null;

switch (brand)
{
case "Lenovo":nb = new Lenovo();
break;
case "IBM":nb = new IBM();
break;
case "Acer":nb = new Acer();
break;
case "Dell":nb = new Dell();
break;
default:
break;
}

return nb;
}
}
public abstract class NoteBook
{
public abstract void SayHello();
}
public class Lenovo : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是联想笔记本");
}
}
public class Acer : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是鸿基笔记本");
}
}
public class Dell : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是戴尔笔记本");
}
}
public class IBM : NoteBook
{
public override void SayHello()
{
Console.WriteLine("我是IBM笔记本");
}
}
}

值类型:int,double,char,decimal,bool,enum,struct
复制时,传递的是本身
引用类型:string,数组,自定义类,集合,object,接口
复制时,传递的是地址 注意:字符串的不可变型

加ref:值传递->引用传递

序列化和反序列化:
序列化:就是将对象转换为二进制
在类上加[Serializable]

反序列化:就是将二进制转换为对象

作用:传递数据

部分类:在类的class前加partial,可以写相同类

密封类:在类的class前加sealed,不能被继承,但是可以继承其他类

重写toString方法:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;

namespace 重写toString方法
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
Console.WriteLine(p.ToString());
Console.ReadKey();
}
}
public class Person
{
public override string ToString()
{
return "Hello World";
}
}
}
案例: 超市收银系统

商品类、

GUID:产生一个不会重复的编号 Guid.NewGuid().toString()

代码:

ProductFather.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class ProductFather
{
public double Price
{
get;
set;
}
public string Name
{
get;
set;
}
public string ID
{
get;
set;
}
public ProductFather(string id,double price,string name)
{
this.ID = id;
this.Name = name;
this.Price = price;
}
}
}

Acer.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class Acer:ProductFather
{
public Acer(string id,double price,string name)
: base(id, price, name)
{

}
}
}

SamSung.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class SamSung:ProductFather
{
public SamSung(string id,double price,string name)
: base(id, price, name)
{

}
}
}

JiangYou.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class JiangYou:ProductFather
{
public JiangYou(string id,double price,string name)
: base(id, price, name)
{

}
}
}

Banana.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class Banana:ProductFather
{
public Banana(string id,double price,string name)
: base(id, price, name)
{

}
}
}

CangKu.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class CangKu
{
//存储货物 使用父类
List<List<ProductFather>> list = new List<List<ProductFather>>();

/// <summary>
/// 向用户展示货物
/// </summary>
public void ShowPros()
{
foreach (var item in list)
{
Console.WriteLine("仓库有:"+item[0].Name+"\t\t"+"有"+item.Count+"个"+"\t\t每个"+item[0].Price+"元");
}
}
//list[0]存放Acer电脑
//list[1]存放三星手机
//list[2]存放酱油
//list[3]存放酱油
/// <summary>
/// 在创建仓库对象时 向仓库中添加货架
/// </summary>
public CangKu()
{
list.Add(new List<ProductFather>());
list.Add(new List<ProductFather>());
list.Add(new List<ProductFather>());
list.Add(new List<ProductFather>());
}
/// <summary>
/// 进货
/// </summary>
/// <param name="strType">货物类型</param>
/// <param name="count">货物数量</param>
public void JinPros(String strType,int count)
{
for (int i = 0; i < count; i++)
{
switch(strType)
{
case "Acer":
list[0].Add(new Acer(Guid.NewGuid().ToString(),1000,"鸿基笔记本"));
break;
case "SamSung":
list[1].Add(new SamSung(Guid.NewGuid().ToString(), 800, "三星手机"));
break;
case "JiangYou":
list[2].Add(new JiangYou(Guid.NewGuid().ToString(), 8, "酱油"));
break;
case "Banana":
list[3].Add(new Banana(Guid.NewGuid().ToString(), 3, "香蕉"));
break;
}
}
}
/// <summary>
/// 从仓库中去货物
/// </summary>
/// <param name="strType"></param>
/// <param name="count"></param>
/// <returns></returns>
public ProductFather[] QuPros(String strType, int count)
{
ProductFather[] pros = new ProductFather[count];

for (int i = 0; i < pros.Length; i++)
{
switch (strType)
{
case "Acer":
pros[i]=list[0][0];
list[0].RemoveAt(0);
break;
case "SamSung":
pros[i] = list[1][0];
list[1].RemoveAt(0);
break;
case "JiangYou":
pros[i] = list[2][0];
list[2].RemoveAt(0);
break;
case "Banana":
pros[i] = list[3][0];
list[3].RemoveAt(0);
break;
default:
break;
}
}
return pros;
}
}
}

SupperMarket.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class SupperMarket
{
//创建仓库对象
CangKu ck = new CangKu();
/// <summary>
/// 创建超市对象时给仓库货架上导入货物
/// </summary>
public SupperMarket()
{
ck.JinPros("Acer", 1000);
ck.JinPros("SamSung", 1000);
ck.JinPros("JiangYou", 1000);
ck.JinPros("Banana", 1000);

}
/// <summary>
/// 与用户交互
/// </summary>
public void AskBuying()
{
Console.WriteLine("欢迎光临,请问你要什么");
Console.WriteLine("我们有Acer、SamSung、JiangYou、Banana");
string strType = Console.ReadLine();
Console.WriteLine("你需要多少");
int count = Convert.ToInt32(Console.ReadLine());
//去仓库取货
ProductFather[] pros = ck.QuPros(strType, count);
double realMoney = GetMoney(pros);
Console.WriteLine("你总共消费{0}元", realMoney);
Console.WriteLine("请选择打折方式:1--不打折,2--打9折,3--打85折,4--满300减50,5--满500减100");
string input = Console.ReadLine();
//通过简单工厂设计模式根据用户输入获得一个打折对象
CalFather cal = GetCal(input);
double totalMoney=cal.GetTotalMoney(realMoney);
Console.WriteLine("打折后价钱:{0}", totalMoney);
Console.WriteLine("以下是你的小票:");
foreach (var item in pros)
{
Console.WriteLine("货物名称:{0}\t货物单价:{1}\t货物编号:{2}", item.Name, item.Price, item.ID);
}
}
/// <summary>
/// 根据用户选择的打折方式返回一个打折对象
/// </summary>
/// <param name="input">用户选择</param>
/// <returns>返回的是父类对象 但是里面装的是子类对象</returns>
public CalFather GetCal(string input)
{
CalFather cal = null;
switch (input)
{
case "1":
cal=new CalNormal();
break;
case "2":
cal = new CalRate(0.9);
break;
case "3":
cal = new CalRate(0.85);
break;
case "4":
cal = new CalMN(300,50);
break;
case "5":
cal = new CalMN(500,100);
break;
default:
break;
}
return cal;

}
/// <summary>
/// 根据用户买的货物计算总价钱
/// </summary>
/// <param name="pros"></param>
/// <returns></returns>
public double GetMoney(ProductFather[] pros)
{
double realMoney = 0;
for (int i = 0; i < pros.Length; i++)
{
realMoney += pros[i].Price;
}
return realMoney;
}
public void ShowPros()
{
ck.ShowPros();
}
}
}

CalFather.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
abstract class CalFather
{
/// <summary>
/// 计算打折后价钱
/// </summary>
/// <param name="realMoney">打折前的价钱</param>
/// <returns>打折后的价钱</returns>
public abstract double GetTotalMoney(double realMoney);
}
}

CalNormal.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class CalNormal : CalFather
{
/// <summary>
/// 不打折
/// </summary>
/// <param name="realMoney"></param>
/// <returns></returns>
public override double GetTotalMoney(double realMoney)
{
return realMoney;
}
}
}

CalRate.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class CalRate : CalFather
{
/// <summary>
/// 折扣率
/// </summary>
public double Rate
{
get;
set;
}
public CalRate(double rate)
{
this.Rate = rate;
}
public override double GetTotalMoney(double realMoney)
{
return realMoney * this.Rate;
}
}
}

CalMN.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 超市收银系统
{
class CalMN : CalFather
{
public double M
{
get;
set;
}
public double N
{
set;
get;
}
public CalMN(double m,double n)
{
this.M = m;
this.N = n;
}
public override double GetTotalMoney(double realMoney)
{
if(realMoney>=this.M)
{
return realMoney - (int)(realMoney / this.M) * this.N;
}
else
{
return realMoney;
}
}
}
}

Main.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;

namespace 超市收银系统
{
class Program
{
static void Main(string[] args)
{
//创建超市对象
SupperMarket sm = new SupperMarket();
//展示货物
sm.ShowPros();
//用户交互
sm.AskBuying();
Console.ReadKey();
}
}
}
MD5加密

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Security.Cryptography;
using System.Text;

namespace MD5加密
{
class Program
{
static void Main(string[] args)
{
//"123" 202cb962ac59075b964b07152d234b70
string s = GetMD5("123");
Console.WriteLine(s);
Console.ReadKey();
}
public static string GetMD5(string str)
{
//创建MD5对象
MD5 md5 = MD5.Create();
//加密
//将字符串转化为字节数组
byte[] buffer = Encoding.Default.GetBytes(str);
byte[] MD5Buffer = md5.ComputeHash(buffer);
//将字节数组转化为字符串
//将字节数组中每一个元素按照指定的编码格式解析成字符串
//直接将数组ToString()
//将字节数组中每个元素ToString()
//return Encoding.Default.GetString(MD5Buffer);
string strs = "";
for (int i = 0; i < MD5Buffer.Length; i++)
{
strs += MD5Buffer[i].ToString("x2");//将10进制转化为16进制:x x2起对齐作用
}
return strs;
}
}
}

5 winform

winform应用程序是一种智能客户端技术,我们可以使用winform应用程序帮助我们获得信息或者传输信息等

创建时选择Windows窗体应用(.NET Framework)

后台切前台:右键->查看设计器

Button控件

属性:
1.Name:在后台要获得前台的空间对象时需要使用Name属性
2.visible:指示一个控件是否可见
3.Enabled:指示一个控件是否可用

事件:
注册事件:双击控件注册的都是控件默认选中的那个事件
触发事件:

在Main函数中创建的窗体对象我们称之为这个窗体应用程序的主窗体

关闭所有窗体:

新建一个静态类

1
2
3
4
public static class Test
{
public static Form1 _fr1Test;
}

主窗体load加载时发生:

1
Test._fr1Test = this;

需要调用关闭事件的地方:

1
Test._fr1Test.Close();

Button常用事件:Click、MouseEnter

TextBox控件

属性:
1.WordWrap:指示文本框是否换行
2.PasswordChar:让文本框显示一个单一的字符
3.ScollBars:是否显示滚动条
事件:TextChanged:当文本框中内容改变时执行这个事件

Timer
在指定的一段时间间隔内
事件:Tick:每隔一段时间执行一次事件

播放音乐:

1
2
3
SoundPlayer sp = new SoundPlayer();
sp.SoundLocation = @"音乐文件路径(只支持.wav)";
sp.play();

CheckBox 复选框

checked:指示这个空间是否选中

RadioButton 单选

默认情况下,在一个窗体中,所有单选按钮只允许选中一个,但可以使用GroupBox容器:用于分组

MDI窗体设计

1.首先确定一个父窗体
isMdiContainer -> true
2.创建子窗体,并且设置他们的父窗体

代码

PictureBox

.Image = Image.FromFile(图片全路径);

Directory 操作文件夹

CreateDirectory 创建文件夹
Delete 删除文件夹
Move 剪切文件夹
Exist 判断是否存在
GetFiles 获得指定目录下所有文件的全路径
GetDirectory 获得指定目录下所有文件夹的全路径

WebBrowser 浏览器控件

Url:网站网址

Uri uri = new Uri(“http://”+str);

ComboBox 下拉框控件

DropDownStyle:控制下拉框的外观样式

名字:cbo+…

.Items.Add()//添加
.Items.Clear()//清空
.SelectedItem.ToString()//获取当前选择的文本

案例: 日期选择器

代码

ListBox控件

.Items.Add()//添加

案例: 石头剪刀布

代码

对话框

打开对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
OpenFileDialog ofd = new OpenFileDialog();
//设置对话框标题
ofd.Title = "";
//设置对话框可以多选
ofd.Multiselect = true;
//设置对话框初始目录
ofd.InitialDirectory = @"全路径";
//设置对话框的文件类型
ofd.Filter = "文本文件|*.txt|媒体文件|*.wmv|图片文件|*.jpg|所有文件|*.*";
//展示对话框
ofd.ShowDialog();
//获得在打开对话框中选中文件的路径
string path = ofd.FileName;
if(path=="")
{
return;
}
using(FileStream fsRead = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Read))
{
byte[] buffer = new byte[1024*1024*5];
int r = fsRead.Read(buffer,0,buffer.Length);
textBox.Text = Encoding.Default.GetString(buffer,0,r);
}

保存对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SaveFileDialog sfd = new SaveFileDialog();
sfd.Title = "";
sfd.InitialDirectory = @"全路径";
sfd.Filter = "文本文件|*.txt|媒体文件|*.wmv|图片文件|*.jpg|所有文件|*.*";
sfd.ShowDialog();
string path = sfd.FileName;
if(path=="")
{
return;
}
using(FileStream fsWrite = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
{
byte[] buffer = Encoding.Default.GetBytes(textBox.Text);
fsWrite.Write(buffer,0,buffer.Length);
}
MessageBox.Show("保存成功");

字体和颜色对话框

1
2
3
4
5
6
7
FontDialog fd = new FontDialog();
fd.ShowDialog();
textBox.Font = fd.Font;

ColorDialog cd = new ColorDialog();
cd.ShowDialog();
textBox.ForeColor = cd.Color;

panel.Visibel = false;//隐藏

进程类

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Diagnostics;

namespace 进程类
{
class Program
{
static void Main(string[] args)
{
//获取当前程序所有正在运行的进程
/*
Process[] pros = Process.GetProcesses();
foreach (var item in pros)
{
Console.WriteLine(item);
}
*/
//Process.Start("calc");//打开计算机
//打开指定文件
ProcessStartInfo psi = new ProcessStartInfo(@"E:\test.txt");
//1.创建进程对象
Process p = new Process();
p.StartInfo = psi;
p.Start();
Console.ReadKey();
}
}
}

多线程

线程分类:

  • 前台线程:只有所有前台线程都关闭才能完成程序关闭
  • 后台线程:只要所有前台线程结束,后台线程自动关闭

单线程问题:

  • 假死
  • 耗时
1
2
3
4
5
6
7
8
Thread th;

//创建一个线程
th = new Thread(Test);
//将线程设置为后台线程
th.IsBackground = true;
//标记这个线程准备就绪,随时可以被执行
th.Start();

.NET下不允许跨线程访问

1
2
//取消跨线程访问
Control.CheckForIllegalCrossThreadCalls = false;

关闭窗体时判断新线程是否为null,避免主线程关闭,新线程未关闭

Closing

1
2
3
4
5
if(th != null)
{
//结束这个线程
th.Abort();//一旦Abort就不能Start了
}

Thread.Sleep(3000);//休眠3秒

Socket网络编程

如果线程执行的方法需要参数,那么要求这个参数必须是object类型

1
2
3
4
5
6
7
8
9
10
11
12
13
Thread th = new Thread(Test);
th.IsBackground = true;
th.Start("123");

//下面是Test方法
private void Test(object s)
{
string ss = (string)s;
for(int i = 0;i < 10000;i++)
{
Console.WriteLine(i);
}
}

TCP:3次握手 安全、稳定但效率低
UDP:快速、效率高,但是不稳定 容易发生数据丢失

服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
try{
//创建一个负责监听的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//创建IP地址和端口号对象
IPAddress ip = IPAddress.Any; //IPAddress.Parse(txtServer.Text);
IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(txtPort.Text));//第二个参数为端口号
//让负责监听的Socket绑定IP地址的端口号
socketWatch.Bind(point);
ShowMsg("监听成功");
//设置监听队列 在某一个时间点内能够连入这个服务端的最大客户端数量
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}catch
{}

Socket socketSend;

//等待客户端的连接 并且创建与之通信的Socket
void Listen(object o)
{
//负责跟客户端通信的Socket 将远程地址的端口号存在下拉列表中
Socket socketWatch = o as Socket;
//负责监听的Socket 来接收客户端的连接 创建跟客户端通信的Socket
while(true)
{
try
{
socketSend = socketWatch.Accept();
//将远程连接的客户端的IP地址和Socket存入集合中
dicSocket.Add(socketSend.RemoteEndPoint.ToString(),socketSend);
//将远程连接的客户端IP地址和端口号存入下拉框中
cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
//RemoteEndPoint 得到远程地址的端口号
ShowMsg(socketSend.RemoteEndPoint.ToString()+":"+"连接成功");
//开启一个新线程 不同接收客户端发来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start(socketSend);
}
catch
{}
}
}

//将远程连接的客户端的IP地址和Socket存入集合中
Dictionary<string,Socket> dicSocket = new Dictionary<string,Socket>();

//服务器端不停接收客户端发送的消息
void Recive(object o)
{
Socket socketSend = o as Socket;
while(true)
{
try
{
//客户端连接成功后 服务器应该接收客户端发来的消息
byte[] buffer = new byte[1024*1024*2];
//r 实际接收到的有效字节数
int r = socketSend.Receive(buffer);
if(r==0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer,0,r);
ShowMsg(socketSend.RemoteEndPoint+":"+str);
}catch
{}
}
}
void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}

//服务端个客户端发送消息 点击事件
string str = txtMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(buffer);
//将泛型集合转化为数组
byte[] newBuffer = list.ToArray();
//获得在下拉框中选择的IP地址
string ip = cboUsers.SelectedItem.ToString();
dicSocket[ip].Send(newBuffer);
//socketSend.Send(buffer);

//选择要发送的文件 按钮点击事件
OpenFileDialog ofd =new OpenFileDialog();
ofd.InitialDirectory = @"初始目录全路径";
ofd.Title = "请选择要发送的文件";
ofd.Filter = "所有文件|*.*";
ofd.ShowDialog();
txtPath.Text = ofd.FileName;

//按钮点击事件
string path = txtPath.Text;
using(FileStream fsRead = new FileStream(path,FileMode.Open,FileAccess.Read))
{
byte[] buffer = new byte[1024*1024*5];
int r = fsRead.Read(buffer,0,buffer.Length);
List<byte>list = new List<byte>();
list.Add(1);
list.AddRange(buffer);
byte[] newBuffer = list.ToArray();
dicSocket[cboUsers.SelectedItem.ToString()].Send(newBuffer,0,r+1,SocketFlags.None);
}

//震动 按钮点击事件
byte[] buffer = new byte[1];
buffer[0] = 2;
dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer);

//解决线程间操作不到问题
//在程序加载时取消跨线程的检查
Control.CheckForIllegalCrossThreadCalls = false;

打开Telnet Client:
控制面板->查看方式(类别)->程序->程序和功能->启用或关闭Windows功能(在左边)->Telnet Client(勾上),点击确认

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
Socket socketSend;

try{
//创建负责通讯的Socket
socketSend = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(txtServer.Text);
IPEndPoint point = new IPEndPoint(ip,Convert.ToInt32(txtPort.Text));
//获得要连接的远程服务器应用程序的IP地址和端口号
socketSend.Connect(point);
ShowMsg("连接成功");
//开启新线程不停接收服务端发来的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start();
}catch
{}

//不停接收服务端发来的消息
void Recive()
{
try{
while(true)
{
byte[] buffer = new byte[1024*1024*3];
int r = socketSend.Receive(buffer);
//实际接收到的有效字节数组
if(r==0)
{
break;
}
if(buffer[0]==0)
{
//发送文字消息
string s = Encoding.UTF8.GetString(buffer,1,r-1);
ShowMsg(socketSend.RemoteEndPoint+":"+s);
}else if(buffer[0]==1)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = @"保存默认地址";
sfd.Title = "请选择要保存的文件";
sfd.Filter = "所有文件|*.*";
sfd.ShowDialog(this);
string path = sfd.FileName;
using(FileStream fsWrite = new FileStream(path,FileMode.OpenOrCreate,FileAccess.Write))
{
fsWrite.Write(buffer,1,r-1);
}
MessageBox.Show("保存成功");
}else if(buffer[0]==2)
{
ZD();
}
}
}catch
{}
}

//震动
void ZD()
{
for(int i = 0;i < 500;i++)
{
this.Location = new Point(200,200);
this.Location = new Point(280,280);
}
}

//发送消息事件中
string str = txtMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send();

void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}

//解决线程间操作不到问题
//在程序加载时取消跨线程的检查
Control.CheckForIllegalCrossThreadCalls = false;

开启多个项目:右键项目->调试->启动新实例

设计"协议":

  • 0 文本
  • 1 文件
  • 2 震动

GDI绘图

保留2位小数: avg = Convert.ToDouble(avg.ToString("0.00"));

窗体事件:Print
窗体重新绘制时都会画一遍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//创建GDI对象
Graphics g = this.CreateGraphics();
//创建画笔对象
Pen pen = new Pen(Brushes.Red);
//扇形
Size sizePie = new System.Drawing.Size(80, 80);
Rectangle recPie = new Rectangle(new Point(150, 150), sizePie);
g.DrawPie(pen, recPie, 60, 60);
//矩形
Size size = new System.Drawing.Size(80, 80);
Rectangle rec = new Rectangle(new Point(50,50),size);
g.DrawRectangle(pen, rec);
//创建俩个点
Point p1 = new Point(30, 50);
Point p2 = new Point(25, 250);
g.DrawLine(pen, p1, p2);
案例: 验证码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void pictureBox1_Click(object sender, EventArgs e)
{
Random r = new Random();
string str = null;
for (int i = 0; i < 5; i++)
{
int rNumber = r.Next(0, 10);
str += rNumber;
}
//MessageBox.Show(str);
//创建GDI对象
Bitmap bmp = new Bitmap(110,30);
Graphics g = Graphics.FromImage(bmp);
for (int i = 0; i < 5; i++)
{
Point p = new Point(i*20,0);
string[] fonts = { "微软雅黑", "宋体", "隶书", "黑体", "仿宋" };
Color[] colors = { Color.Yellow, Color.Blue, Color.Green, Color.Black, Color.Red };
g.DrawString(str[i].ToString(),new Font(fonts[r.Next(0,5)],20,FontStyle.Bold),new SolidBrush(colors[r.Next(0,5)]),p);
}
for (int i = 0; i < 20; i++)
{
Point p1 = new Point(r.Next(0,bmp.Width),r.Next(0,bmp.Height));
Point p2 = new Point(r.Next(0,bmp.Width),r.Next(0,bmp.Height));
g.DrawLine(new Pen(Brushes.Green),p1,p2);
}
for (int i = 0; i < 500; i++)
{
Point p = new Point(r.Next(0, bmp.Width), r.Next(0, bmp.Height));
bmp.SetPixel(p.X,p.Y,Color.Black);
}
//将图片镶嵌到PictureBox中
pictureBox1.Image = bmp;

代码

案例: 简单播放器

添加Windows Media Player
工具箱里找到组件右键->选择项->COM组件->找到Windows Media Player勾上并确认

windows media player控件的常用属性和方法

以下 music player 均为windows media player控件的名字。
1.属性
1)musicPlayer.settings.autoStart:打开播放器时是否自动播放 。true:自动播放,false:不自动播放,默认自动播放。
2)musicPlayer.URL:要播放歌曲的路径。
3)musicPlayer.settings.mute:是否静音。true:静音,false:不静音。
4)musicPlayer.settings.volume:音量值大小,范围是1 ~ 100。
5)musicPlayer.Ctlcontrols.currentPositionString:当前播放时间。返回值是字符串类型,例如:02:23。
6)musicPlayer.Ctlcontrols.currentPosition:也是返回当前播放的时间。返回值是 double 类型,例如:133.8。
7)musicPlayer.currentMedia.name:返回当前播放歌曲的名字。
8)musicPlayer.playState:播放器当前的状态。

  • 有一个枚举 WMPLib.WMPPlayState 说明了它的取值:
    0——wmppsUndefined:未知状态
    1——wmppsStopped:播放停止
    2——wmppsPaused:播放暂停
    3——wmppsPlaying:正在播放
    4——wmppsScanForward:向前搜索
    5——wmppsScanReverse:向后搜索
    6——wmppsBuffering :正在缓冲
    7——wmppsWaiting:正在等待流开始
    8——wmppsMediaEnded:播放流已结束
    9——wmppsTransitioning :准备新的媒体文件
    10——wmppsReady:播放准备就绪
    11——wmppsReconnecting:尝试重新连接流媒体数据
    12——wmppsLast:上一次状态,状态没有改变

2.方法
1)musicPlayer.Ctlcontrols.play():播放
2)musicPlayer.Ctlcontrols.pause():暂停
3)musicPlayer.Ctlcontrols.stop():停止

属性:
url:音乐地址

1.在程序加载时取消播放器自动播放功能
2.播放或者暂停按钮
3.上一曲、下一曲
4.多选删除

  • 给ListBox添加一个右键菜单
    5.静音和放音
    6.选择列表中的音乐文件,单击按钮直接播放
    7.自动播放下一曲

代码

HTML

需要安装组件ASP.net 和 Web开发中的其他项目模板(早期版本)

  • 位置:展开最右边的ASP.NET和Web开发下拉菜单

新建网站项目:
选择ASP.NET 空网站这个选项即可
添加html页:右键项目->添加->添加新项->HTML页

HTML:超文本标记语言

标签:

  • p: 段落标签
  • &nbsp: 空格
  • h#: 标题标签
  • <!-- 要注释的内容 -->: 注释符
  • <img/>: 图片标签
    • src: 要显示图片的路径
    • height: 图片高度
    • width: 图片宽度
    • alt: 图片显示失败所显示的文本
    • title: 光标移动到图片上所显示的文本
  • <hr/>: 分割线
  • <font></font>: 字体标签
    • size=1 ~ 7 最大:7
    • color: 颜色
    • face: 字体系列
  • a标签:
    • href: 要连接的地址
    • target: 打开新网页的方式(_blank:打开一个新的页面;_self:当前页面跳转)
      作用:
      1.实现页面内的跳转
      2.实现页面间的跳转
      3.发送邮件
  • div+span
  • frame: 框架标签

更多请查看HTML

CSS

CSS:控制网页内容的效果

更多请查看CSS

委托、XML、播放器项目

单例模式
1.将构造函数私有化
2.提供一个静态方法,返回一个对象
3.创建一个单例

XML:可扩展标记语言

  • 存储数据
    注意:XML严格区分大小写且也是成对出现
    XML文档有且只有一个根节点

节点
元素

通过代码创建XML文档
1.引用命名空间

  • using System.Xml;
    2.创建XML文档对象
  • XmlDocument doc = new XmlDocument();
    追加文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
XmlElement root;
if(File.Exists("xxx.xml"))
{
//文件存在 加载XML
doc.Load("xxx.xml");
//获取文件根节点
root = doc.DocumentElement;
}
else
{
//文件不存在
//创建第一行描述信息,并添加到文档中
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0","utf-8",null);
doc.AppendChild(dec);
//创建根节点
root = doc.CreateElement("xxx");
doc.AppendChild(root);
}

读取XML文档

1
2
3
4
5
6
7
8
9
doc.Load("xxx.xml");
//获取文件根节点
XmlElement root = doc.DocumentElement;
//获得子节点 返回结点集合
XmlNodeList xnl = root.ChildNodes;
foreach(XmlNode item in xnl)
{
Console.WriteLine(item.InnerText);
}

读取带属性XML文档

1
2
3
4
5
6
doc.Load("xxx.xml");
XmlNodeList xnl = doc.SelectNodes("/xxx/xxx");//找到节点
foreach(XmlNode node in xnl)
{
Console.WriteLine(node.Attributes["属性名"].Value);
}

删除节点

1
2
3
4
doc.Load("xxx.xml");
XmlNode xn = doc.SelectSingleNode("/xxx/xxx");
xn.RemoveAll();
doc.Save("xxx.xml");

3.创建第一行描述信息,并添加到文档中

  • XmlDeclaration dec = doc.CreateXmlDeclaration("1.0","utf-8",null);
  • doc.AppendChild(dec);
    4.创建根节点
  • XmlElement root = doc.CreateElement("xxx");
  • doc.AppendChild(root);
    5.创建子节点
  • XmlElement child = doc.CreateElement("xxxxx");
    6.给根节点添加子节点
    child.InnerText = ""; 添加文本
    child.InnerXml = ""; 添加标签
    child.setAttribute("属性名","属性值"); 添加属性
  • root.AppendChild(child);
  • doc.Save("xxx.xml");

保存的文件放在bin目录下

委托

1.为什么使用委托

将一个方法作为参数传递给另一个方法

2.委托概念

声明一个委托类型(命名空间下)
public delegate void func(参数类型,参数名);
委托所指向的函数必须跟委托具有相同的签名(参数和返回值)

3.匿名函数

没有名字的函数
函数只调用一次时建议使用匿名函数
匿名函数必须跟委托具有相同的签名(参数和返回值)

4.练习:使用委托求数组最大值
5.练习:使用委托求任意数组最大值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;

namespace 委托求数组最大值
{
class Program
{
public delegate int DelCompare(object o1,object o2);
static void Main(string[] args)
{
object[] o1 = { 1, 2, 3, 4, 5 };
object result1 = GetMax(o1, Compare1);
object[] o2 = { "vhgfh","yuewueg","fdg" };
//object result2 = GetMax(o2, Compare2);
//object result2 = GetMax(o2, delegate(object o1,object o2) {
// string s1 = (string)o1;
// string s2 = (string)o2;
// return s1.Length - s2.Length;
//});
object result2 = GetMax(o2, (object o1,object o2) =>{
string s1 = (string)o1;
string s2 = (string)o2;
return s1.Length - s2.Length;
});
Console.WriteLine(result2);
Console.ReadKey();
}
public static object GetMax(object []nums,DelCompare del)
{
object max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
//要传一个比较方法
if(del(max,nums[i])<0)
{
max = nums[i];
}
}
return max;
}
public static int Compare1(object o1,object o2)
{
int n1 = (int)o1;
int n2 = (int)o2;
return n1 - n2;
}
public static int Compare2(object o1, object o2)
{
string s1 = (string)o1;
string s2 = (string)o2;
return s1.Length - s2.Length;
}
}
}

6.泛型委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;

namespace 泛型委托求数组最大值
{
class Program
{
public delegate int DelCompare<T>(T o1,T o2);
static void Main(string[] args)
{
int[] nums= { 1, 2, 3, 4, 5 };
int result1 = GetMax<int>(nums, Compare1);
string[] str = { "vhgfh","yuewueg","fdg" };
string result2 = GetMax<string>(str, (string s1, string s2) =>
{
return s1.Length - s2.Length;
});
Console.WriteLine(result2);
Console.ReadKey();
}
public static T GetMax<T>(T []nums,DelCompare<T> del)
{
T max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
//要传一个比较方法
if(del(max,nums[i])<0)
{
max = nums[i];
}
}
return max;
}
public static int Compare1(int n1,int n2)
{
return n1 - n2;
}
public static int Compare2(string s1, string s2)
{
return s1.Length - s2.Length;
}
}
}

7.多播委托

委托可以指向多个函数,但要满足指向的函数必须跟委托具有相同的签名(参数和返回值)
可以使用= += 操作

8.lambda表达式

(参数)=>{方法体} => goes to
eg:
list.RemoveAll(n => n > 4); //移除大于4的元素

9.使用委托实现窗体传值

代码