C#知识
C#知识
1.程序调试
- 写完一段程序后,想看一下这段程序的执行过程。
- 当你写完这段程序后,发现,程序并没有按照你想象的样子去执行。
1.1 调试方法
- F11逐语句调试(单步调试)
- F10逐过程调试
- 断点调试
1.2 随机数
static void Main(string[] args)
{
//产生随机数
//1.创建能够产生随机数的对象
Random r = new Random();
while (true)
{
//2.让产生随机数的这个对象调用方法来产生随机数
int rNumber = r.Next(1, 11);
Console.WriteLine(rNumber);
Console.ReadKey();
}
//输入名字随机显示这个人上辈子是什么人
}
1.3 随机数练习
//输入名字随机显示这个人上辈子是什么人
//思路:
//1.创建能够产生随机数的对象
//2.产生随机数(1,7)
Random r = new Random();
while (true)
{
int rNumber = r.Next(1, 7);
Console.WriteLine("请输入一个名字");
string name = Console.ReadLine();
switch (rNumber)
{
case 1:
Console.WriteLine("{0}上辈子是商人", name);
break;
case 2:
Console.WriteLine("{0}上辈子是军人", name);
break;
case 3:
Console.WriteLine("{0}上辈子是书生", name);
break;
case 4:
Console.WriteLine("{0}上辈子是官员", name);
break;
case 5:
Console.WriteLine("{0}上辈子是农民", name);
break;
case 6:
Console.WriteLine("{0}上辈子是司机", name);
break;
}
Console.ReadKey();
}
1.4 三元表达式
- 语法:
- 表达式1?表达式2:表达式3;
- 表达式1一般为一个关系表达式。
- 如果表达式1的值为true,那么表达式2的值就是整个三元表达式的值。
- 如果表达式的值为false,那么表达式3的值 就是整个三元表达式的值。
- 注意:表达式2的结果类型必须跟表达式3的结果类型一致,并且也要跟整个三元表达式的结果类型一致。
static void Main(string[] args)
{
//计算两个数字的大小 求出最大的
Console.WriteLine("请输入第一个数字");
int n1 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("请输入第二个数字");
int n2 = Convert.ToInt32(Console.ReadLine());
//表达式1?表达式2:表达式3;
int max = n1 > n2 ? n1 : n2;
Console.WriteLine(max);
Console.ReadKey();
}
2.数据类型
2.1 变量类型
-
int double string char bool decimal
-
变量的使用规则:先声明再赋值最后使用
-
int number; number = 10; Console.WriteLine(number);
2.2.1 运算符
- 赋值运算符:=
- 复合赋值运算符: += -= *= /= %= sum+=age; sum=sum+age;
- 算数运算符: + - * / % ++ --
- 关系运算符: > < >= <= == !=
- 逻辑运算符: && || !
2.2 C#中的语法结构
-
分支结构
-
if if-else -
选择结构:
-
while do-while for
2.3 常量
- 声明的常量 的语法: const 变量类型 变量名=值;
2.4 枚举
语法:
[public] enum 枚举名{
值1,
值2,
值3,
....
}
- public:访问修饰符,公共的公开的,哪都可以访问。
- enum:关键字,声明枚举的关键字
- 枚举名:要符合Pascal命名规范
- 将枚举声明到命名空间的下面,类的外面,表示这个命名空间下,所有的类都可以使用这个枚举
- 枚举就是一个变量类型,只是枚举声明,赋值,使用的方式跟那些普通的变量类型不一样
- 枚举类型默认是跟Int类型相互兼容的,所以可以通过强制类型转换的语法互相转换,当转换一个枚举中没有值的时候,不会抛异常,而是直接将数字显示出来。
- 枚举同样也可以跟string类型互相转换,如果将枚举类型转换成string类型,则直接调用ToString(),如果将字符串转换成枚举类型则需要下面一行代码: (要转换的枚举类型)Enum.Parse(typeof(要转换的枚举类型),"要转换的字符串"); ----如果转换的字符串是数字,则就算枚举中没有,也不会抛异常;如果转换的字符串是文本,如果枚举中没有,则会抛出异常。
- 所有的类型都能够转换成string类型,调用ToString()
- typeof --获取谁的类型
namespace _22_3_枚举练习
{
public enum Sesons
{
春,
夏,
秋,
冬
}
public enum QQState
{
Online,
OffLine,
Leave,
Busy,
QMe
}
class Program
{
static void Main(string[] args)
{
QQState state = QQState.Leave;
Sesons s = Sesons.春;
}
}
}
2.5 结构
-
可以帮助我们一次性声明多个不同类型的变量。
语法:
[public] struct 结构名 { 成员;//字段 }变量在程序运行期间只能存储一个值,而字段可以存储多个值。
2.6 数组
-
一次性存储多个相同类型的变量。
-
语法:数组类型[] 数组名=new 数组类型[数组长度];
-
数组的长度一旦固定了,就不能再被改变了
-
数组声明方式
//数组类型[] 数组名=new 数组类型[数组长度]; int[] nums = new int[10]; //数组的声明方式 int[] numsTwo = { 1, 2, 3, 4, 5, 6 }; int[] numsThree = new int[3] { 1, 2, 3 };
2.7 冒泡排序
-
冒泡排序就是将一个数组中的元素按照从大到小或者从小到大的顺序进行排列。
static void Main(string[] args) { int[] nums = { 9,8,7,6,5,4,3,2,1}; Array.Sort(nums); //升序排列 Array.Reverse(nums);//数组反转 for (int i = 0; i < nums.Length; i++) { Console.WriteLine(nums[i]); } Console.ReadKey(); }
2.8 方法
函数就是将一堆代码进行重用的一种机制。
函数的语法:
[public] static 返回值类型 方法名 ([参数列表])
{
方法体;
}
public: 访问修饰符,公开的,公共的,哪都可以访问
static: 静态的
返回值类型:如果不需要返回值,写void
方法名: Pascal 每个单词的首字母都大写,其余字母小写
参数列表:完成这个方法所必须要提供给这个方法的条件。如果没有参数,小括号也不能省略。
return:1.在方法中返回要返回的值。2.立即结束本次方法
方法写好后,如果想要被执行,必须要在Main()函数中调用。
方法的调用语法:
类名.方法名();
***在某些情况下,类名是可以省略的,如果你写的方法跟Main函数在同一个类里,这个时候类名可以省略。
class Program
{
static void Main(string[] args)
{
//计算两个整数之间的最大值
int max = Program.GetMax(1,3);
Console.WriteLine(max);
Console.ReadKey();
}
public static int GetMax(int n1, int n2)
{
return n1 > n2 ? n1: n2;
}
}
2.8.1 方法的调用
-
我们在Main()函数中,调用Test()函数,我们管Main()函数称之为调用者,管Test()函数称之为被调用者。
-
如果被调用者想要得到调用者的值:
-
传递参数
-
static void Main(string[] args) { int a = 3; Test(a); Console.WriteLine(a); Console.ReadKey(); } public static void Test(int a) { a = a + 5; } -
使用静态字段来模拟全局变量
-
-
如果调用者想要得到被调用者的值:
- 返回值
static void Main(string[] args) { //写一个方法,判断一个年份是否是润年 bool b = IsRun(2000); Console.WriteLine(b); Console.ReadKey(); } /// <summary> /// 判断给定的年份是否是闰年 /// </summary> /// <param name="year">要判断的年份</param> /// <returns>是否是闰年</returns> public static bool IsRun(int year) { bool b = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0); return b; } -
方法的功能一定要单一
-
GetMax(int n1, int n2) -
方法中最忌讳的就是出现提示用户输入的字眼
-
2.8.2 高级参数
-
out参数
如果你在一个方法中,返回多个形同类型的值的时候,可以考虑返回一个数组。但是,如果返回多个不同类型的值的时候,返回数组就不行了,那么这个时候,我们考虑使用out参数。
out参数就侧重于在一个方法中返回多个不同类型的值,也能返回相同类型的值。 -
ref参数
能够将一个变量带入一个方法中进行改变,改变完成后,再将改变后的值带出方法。ref参数要求在方法外必须为其赋值,而方法内可以不赋值。
-
params可变参数
将实参列表中跟可变参数数组类型一致的元素都当做数组的元素去处理。
params可变参数必须是形参列表中的最后一个元素。
2.8.3 方法的重载
概念:方法的重载指的就是方法的名称相同,但是参数不同。
参数不同分为两种情况
- 如果参数的个数相同,那么参数的类型就不能相同。
- 如果参数的类型相同,那么参数的个数就不能相同。
- ****方法的重载跟返回值没有关系
2.8.4 方法的递归
- 方法自己调用自己,找到一个文件夹下所有的文件。
2.9 异常处理语句
2.9.1 try...catch...语句
static void Main(string[] args)
{
try
{
checked
{
int Inum1;
int Inum2;
int Num;
Inum1 = 6000000;
Inum2 = 6000000;
Num = Inum1 * Inum2;
}
}
catch (OverflowException)
{
Console.WriteLine("引发OverflowException异常");
}
Console.ReadLine();
OverflowException 异常:溢出异常。这个一般是当在线程检查的上下文中执行的算术、强制转换或转换运算导致溢出时引发的异常。
2.9.2 throw语句
-
throw语句用于主动引发一个异常,使用throw语句可以在特定的情形下,自行抛出异常。
-
throw ExObject -
ExObject:所要抛出的异常对象,这个异常对象是派生自System.Exception类的类对象
-
创建一个int类型的方法MyInt(),此方法有两个string类型的参数a
和b。在这个方法中,使a作分子,b作分母,如果分母的值是0,则通过throw语句抛出
DivideByZeroException异常,这个异常被此方法中的catch子句捕获并输出 -
class Program { class test { public int MyInt(string a,string b) { int int1; int int2; int num; try { int1 = int.Parse(a); int2 = int.Parse(b); if (int2 == 0) { throw new DivideByZeroException(); } num = int1 / int2; return 0; } catch (DivideByZeroException de) { Console.WriteLine("用零除整数引发异常!"); Console.WriteLine(de.Message); return 0; } } } static void Main(string[] args) { try { Console.WriteLine("请输入分子:"); string str1 = Console.ReadLine(); Console.WriteLine("请输入分母:"); string str2 = Console.ReadLine(); test tt = new test(); //调用test类中的MyInt方法,获取键盘输入的分子与分母相除得到的值 Console.WriteLine("分子除以分母的值:"+tt.MyInt(str1,str2)); } catch (FormatException) { Console.WriteLine("请输入数值格式数据"); } Console.ReadLine(); } }
2.9.3 try...catch...finally语句
无论程序是否产生异常,最后都会执行finally语句区块中的程序代码。
/*创建一个控制台应用程序,声明一个string类型变量str,并初始化为“明日科技”。然后声明
一个object变量obj,将str赋给obj。最后声明一个int类型的变量i,将obj强制转换成int类型后赋给变量i,这
样必然会导致转换错误,抛出异常。然后在finally语句中输出“程序执行完毕…”,这样,无论程序是否抛出
异常,都会执行finally语句中的代码*/
class Program
{
static void Main(string[] args)
{
string str = "明日科技";
object obj = str;
try
{
int i = (int)obj;
}
catch (Exception ex)
{
Console.WriteLine("程序执行完毕...");
}
finally
{
Console.WriteLine("程序执行完毕。。");
}
Console.ReadLine();
}
}
3.面向对象
3.1 面向过程
面向过程------->面向对象
面向过程:面向的是完成这件事的过程,强调的是完成这件事的动作。
把大象塞进冰箱里
1.打开冰箱门
2.把大象塞进去
3.关闭冰箱门
面向对象:找个对象帮你做事
- 把大象塞进冰箱里
- 我们把冰箱作为对象:
- 冰箱门可以被打开
- 大象可以被塞进冰箱里
- 冰箱门可以被关闭
3.2 抽象类与抽象方法
3.2.1抽象类概述
C#中声明抽象类时需要使用abstract关键字
声明一个抽象类myClass,该抽象类中声明了两个属性和一
个方法,其中,为两个属性提供了具体实现,方法为抽象方法。然后声明一个派生类DriveClass,继承自
myClass,在DriveClass派生类中重写myClass抽象类中的抽象方法,并提供具体的实现。最后在主程序类
Program的Main()方法中实例化DriveClass派生类的一个对象,使用该对象实例化抽象类,并使用抽象类对象
访问抽象类中的属性和派生类中重写的方法
访问修饰符 abstract class 类名:基类或接口
{
//类成员
}
public abstract class myClass
{
public int i;
public void method()
{}
}
注意:抽象方法必须声明在抽象类中;声明抽象方法时,不能使用virtual、static和private修饰符。
public abstract class myClass
{
private string id = "";
private string name = "";
public string ID //编号属性及实现
{
get
{
return id;
}
set
{
id = value;
}
}
//姓名属性及实现
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public abstract void ShowInfo(); //抽象方法,用来输出信息
}
public class DriveClass : myClass //继承抽象类
{
public override void ShowInfo() //重写抽象类中输出信息的方法
{
Console.WriteLine(ID + "" + Name);
}
}
class Program
{
static void Main(string[] args)
{
DriveClass driveClass = new DriveClass();//实例化派生类
myClass myclass = driveClass; //使用派生类对象实例化抽象类
myclass.ID = "BH0001";//使用抽象类对象访问抽象类中的编号属性
myclass.Name = "TM";//使用抽象类对象访问抽象类中的姓名属性
myclass.ShowInfo();//使用抽象类对象调用派生类中的方法
Console.ReadLine();
}
}
3.3 接口
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。可以将draw()方法封装到一个接口中,使draw()方法的类实现这个接口,同时也继承图形类,这就是接口存在的必要性。
接口是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为。接口可由方法,属性,事件和索引器或这4种成员类型的任何组合构成,但不能包含字段。
类和结构可以像类继承基类或结构一样从接口继承,而且可以继承多个接口。当类或结构继承接口时,它继承成员定义但不继承实现。若要实现接口成员,类中的对应成员必须是公共的,非静态的,并且与接口成员具有相同的名称和标签。
特征:
- 接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
- 不能直接实例化接口。
- 接口可以包含事件、索引器、方法和属性。
- 接口不包含方法的实现。
- 类和结构可从多个接口继承。
- 接口自身可从多个接口继承。
C#中声明接口时,使用interface关键字,其语法格式为
修饰符 interface 接口名称:继承的接口列表
{
接口内容;
}
//可以使用new、public、protected、internal和private等修饰符声明接口,但接口成员必须时公共的。
interface ImyInterface
{
string ID
{
get;set;
}
string Name
{
get;
set;
}
void ShowInfo();
}
/*Program类继承自接口
ImyInterface,并实现了该接口中的所有属性和方法,然后在Main()方法中实例化Program类的一个对象,并
使用该对象实例化ImyInterface接口,最后通过实例化的接口对象访问派生类中的属性和方法*/
interface ImyInterface
{
string ID
{
get; set;
}
string Name
{
get;
set;
}
void ShowInfo();
}
class Program :ImyInterface
{
public string id = "";
string name = "";
public string ID
{
get
{
return id;
}
set
{
id = value;
}
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public void ShowInfo()
{
Console.WriteLine("编号\t 姓名");
Console.WriteLine(ID + "\t" + Name);
Console.ReadLine();
}
static void Main(string[] args)
{
Program program = new Program(); //实例化Program类对象
ImyInterface imyInterface = program; //使用派生类对象实例化接口ImyInterface
imyInterface.ID = "TM"; //为派生类中的ID属性赋值
imyInterface.Name = "c#从入门到精通"; //为派生类中的Name属性赋值
imyInterface.ShowInfo();
}
}
继承多个接口
interface IPeople
{
string Name
{
get;set;
}
string Sex
{
get;set;
}
}
interface ITeacher:IPeople //继承公共接口
{
void teach(); //教学方法
}
interface IStudent:IPeople
{
void study(); //学习方法
}
class Program:IPeople,ITeacher,IStudent // 多接口继承
{
string name = "";
string sex = "";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string Sex
{
get
{
return sex;
}
set
{
sex = value;
}
}
public void teach()
{
Console.WriteLine(Name + ""+Sex+"教师");
}
public void study()
{
Console.WriteLine(Name + "" + Sex + "学生");
}
static void Main(string[] args)
{
Program program = new Program();
ITeacher iteacher = program; //使用派生类对象实例化接口
iteacher.Name = "TM";
iteacher.Sex = "男";
iteacher.teach();
IStudent istudent = program;
istudent.Name = "C#";
istudent.Sex = "男";
istudent.study();
Console.ReadLine();
}
}
3.3.1显式接口
声明了两个接口ImyInterface1和ImyInterface2,在这两个接
口中声明了一个同名方法Add(),然后定义一个类MyClass,该类继承自已经声明的两个接口,在MyClass类
中实现接口中的方法时,由于ImyInterface1和ImyInterface2接口中声明的方法名相同,这里使用了显式接口
成员实现,最后在主程序类Program的Main()方法中使用接口对象调用接口中定义的方法
interface ImyInterface1
{
int Add();
}
interface ImyInterface2
{
int Add();
}
class myClass : ImyInterface1, ImyInterface2 //继承接口
{
/// <summary>
/// 求和方法
/// </summary>
/// <returns>加法运算的和</returns>
int ImyInterface1.Add() //显式接口成员实现
{
int x = 3;
int y = 5;
return x + y;
}
int ImyInterface2.Add()
{
int x = 3;
int y = 5;
int z = 7;
return x + y + z;
}
}
class Program
{
static void Main(string[] args)
{
myClass myClass = new myClass();//实例化接口继承类的对象
ImyInterface1 imyInterface1 = myClass;//使用接口继承类的对象实例化接口
Console.WriteLine(imyInterface1.Add());//使用接口对象调用接口中的方法
ImyInterface2 imyInterface2 = myClass; //使用接口继承类的对象实例化接口
Console.WriteLine(imyInterface2.Add());
Console.ReadKey();
}
}
注意:
-
显式接口成员实现中不能包含访问修饰符、abstract、virtual、override或static修饰符。
-
显式接口成员属于接口的成员,而不是类的成员,因此,不能使用类对象直接访问,只能通过接
口对象来访问。
3.4 委托
c#中的委托(Delegate)是一种引用类型,在委托对象的引用中存放的不是对数据的引用,而是存放对方法的引用,即在委托的内部包含一个指向某个方法的指针。通过使用委托把方法的引用封装在委托对象中,然后将委托对象传递给调用引用方法的代码。
[修饰符] delegate [返回类型] [委托名称] ([参数列表])
3.5事件
3.5.1 委托的发布订阅
由于委托能够引用方法,而且能够链接和删除其他委托对象,因而就能够通过委托来实现事件的“发布
和订阅”这两个必要的过程,通过委托来实现事件处理的过程,通常需要以下4个步骤。
(1)定义委托类型,并在发布者类中定义一个该类型的公有成员。
(2)在订阅者类中定义委托处理方法。
(3)订阅者对象将其事件处理方法链接到发布者对象的委托成员(一个委托类型的引用)上。
(4)发布者对象在特定的情况下“激发”委托操作,从而自动调用订阅者对象的委托处理方法。
下面以学校铃声为例,通常,学生会对上下课铃声做出相应的动作响应,比如:打上课铃,同学们开始学习;打下课铃,同学们开始休息
public delegate void RingEvent(int ringKind);//声明一个委托类型
public class SchoolRing //定义发布者类
{
public RingEvent OnBellSound; //委托发布
public void Jow(int ringKind) //实现打铃操作
{
if (ringKind == 1 || ringKind ==2) //判断打铃是否合法
{
Console.Write(ringKind == 1 ? "上课铃响了,":"下课铃声响了,");
if (OnBellSound != null) //不等于空,说明它已经订阅了具体的方法
{
OnBellSound(ringKind); //回调委托所订阅的具体方法
}
}
else
{
Console.WriteLine("这个铃声参数不正确!");
}
}
}
public class Students //定义订阅者类
{
public void SubscribeToRing(SchoolRing schoolRing) //学生们订阅铃声这个委托事件
{
schoolRing.OnBellSound += SchoolJow; //通过委托的链接操作进行订阅
}
public void SchoolJow(int ringKind) //事件的处理方法
{
if (ringKind == 2)
{
Console.WriteLine("同学们开始课间休息!");
}
else if (ringKind == 1)
{
Console.WriteLine("同学们开始认真学习!");
}
}
public void CancelSubscribe(SchoolRing schoolRing)
{
schoolRing.OnBellSound -= SchoolJow; //取消订阅铃声动作
}
}
class Program
{
static void Main(string[] args)
{
SchoolRing sr = new SchoolRing();
Students student = new Students();
student.SubscribeToRing(sr);
Console.Write("请输入打铃参数(1:上课铃;2:下课铃):");
sr.Jow(Convert.ToInt32(Console.ReadLine()));//开始打铃动作
Console.ReadLine();
}
}
浙公网安备 33010602011771号