实验教程部分











第1章
概述





1.1实验目的及要求
(1) 熟悉Visual Studio 2017开发环境。
(2) 掌握Console类项目的新建与运行。
(3) 掌握WinForm类项目的新建与运行。
(4) 控制台下的简单输出输入。
(5) WinForm下的MessageBox、Label、Button等的简单使用。
1.2实 验 内 容
(1) 熟悉Visual Studio 2017开发环境。
VS开发环境界面如图11所示。




图11VS开发环境




(2) 掌握Console类项目的新建与运行。
要创建Console类项目,首先需要选择“新建”“项目”菜单命令,如图12所示。







图12新建项目


其次,在“新建项目”对话框中选择相应的类型即可,如图13所示。



图13选择控制台应用


为了项目方便维护,一般还应该在图13中设置项目的名称和存储位置,某些特殊情况下,还应选择合适的框架版本。

(3) 控制台下的简单输入输出。
在控制台下,输出主要是通过Console.WriteLine()来实现的。而输入则主要是通过Console.ReadLine()来实现的。


新建Console项目,在Program.cs的Main函数中输入如下语句: 



class Program

{

static void Main(string[] args)

{

//如下是手动输入的代码

Console.WriteLine("请输入您的大名: ");

string sName = Console.ReadLine();//获取用户输入

Console.WriteLine(sName + ",你好");

Console.ReadLine();

}

}







图14CONSOLE程序


按F5键运行程序,效果如图14所示。
(4) 掌握Windows窗体应用(下称WinForm)类项目的新建与运行。
WinForm项目的创建与Console类项目新建方式一样,只是需要选择“Windows窗体应用”即可,其他与控制台类项目完全一样,如图15所示。



图15选择Windows窗体应用


(5) WinForm下的MessageBox、Label、TextBox、Button等的简单使用。
首先新建WinForm项目,往窗体上拖曳一个Label控件,然后选中并右击该Label控件,在快捷菜单中选择“属性”,在“属性窗口”中将label1的Text属性设置为“请输入姓名: ”。
然后往label1控件的后面拖入一个TextBox控件,接着往TextBox控件后拖入一个Button控件,依上述方法,将Button的Text属性修改为“提交”。界面如图16所示。
双击“提交”按钮,输入如下代码: 



private void button1_Click(object sender, EventArgs e)

{

MessageBox.Show("你好,"+textBox1.Text+"!");

}




按F5键运行,结果如图17所示。



图16WinForm界面




图17WinForm程序运行效果














第2章
数据类型与运算符





2.1实验目的及要求
(1) 熟悉常见数据类型。
(2) 熟悉数据类型的转换。
(3) 掌握常见的运算符。
2.2实 验 内 容
计算矩形面积和周长,要求用户输入2个整型数值(即矩形边长),然后计算并输出结果。同时计算该矩形外接圆的面积和周长。
分析: 该题考查了数据类型及其转换,且考查了运算符,同时使用了Math.Sqrt()完成开方运算。
由于矩形边长强制使用整型值,所以边长变量使用int定义即可。另外,由于使用Console.ReadLine()接受的输入为字符串,所以需要完成向整型值的转换,这可以使用int.Parse()或者Convert的相关方法完成。
由于矩形的边长为整数,所以其周长和面积也为整数,不过圆的周长和面积为浮点数,所以为了不再单独为外接圆定义周长和面积变量,故将矩形的周长和面积变量都定义为double类型。
矩形的周长计算公式为: 2×(长+宽)。
矩形的面积计算公式为: 长×宽。
外接圆的面积计算公式为: PI×r2,其中r2=(长×长+宽×宽)/4。
外接圆的周长计算公式为: 2×PI×r。
另外,由于计算圆的周长和面积时,需要用到圆周率的值,该值适合定义为常量。
操作步骤如下: 
首先新建Console项目,在Program.cs中输入如下代码: 



static void Main(string[] args)

{

const double PI = 3.14;

Console.Write("请输入第一个数值并按Enter键:");







string s1 = Console.ReadLine();

Console.Write("请输入第二个数值并按Enter键:");

string s2 = Console.ReadLine();

//将用户输入转换为数值

int d1 = int.Parse(s1);

int d2 = int.Parse(s2);



//计算矩形周长和面积

double c = 2 * (d1 + d2);

double a = d1 * d2;

Console.WriteLine("矩形周长为:" + c.ToString() + ";面积为:" + a.ToString());



//计算外接圆半径的平方值

double r = d1 * d1 / 4 + d2 * d2 / 4;



//计算外接圆的面积

a = PI * r;

c = 2 * PI * Math.Sqrt(r);

Console.WriteLine("矩形外接圆周长为:" + c.ToString() + ";面积为:" + a.ToString());



Console.ReadKey();

}






程序运行结果如图21所示。



图21矩形及外接圆的面积和周长计算


上述程序也可以进行适当简化,例如,下列代码



string s1 = Console.ReadLine();

int d1 = int.Parse(s1);




可简化合并为如下语句



int d1 = int.Parse(Console.ReadLine());




则上述部分代码可精简为: 



Console.Write("请输入第一个数值并按Enter键:");

int d1 = int.Parse(Console.ReadLine());

Console.Write("请输入第二个数值并按Enter键:");

int d2 = int.Parse(Console.ReadLine());















第3章
程 序 控 制







3.1实验目的及要求
(1) 掌握三种类型的程序控制语句: 选择、循环、跳转。
(2) 掌握continue、break、return的特性及适用场合。
3.2实 验 内 容
从键盘上输入两个整数,由用户回答它们的和、差、积、商和取余运算结果,并统计出正确答案的个数。当回答并反馈完毕,询问用户是否继续,若用户回答Y,则继续。
分析: 该题主要考查了算术运算符及if语句和循环语句。代码如下: 



static void Main(string[] args)

{

string sContinue = null;

do

{

Console.WriteLine("请输入两个整数,每输入一个按Enter键结束输入");

int i = int.Parse(Console.ReadLine());

int j = int.Parse(Console.ReadLine());



int iCount = 0; //记录答案正确的个数



Console.Write("请回答和:");

if (i + j == int.Parse(Console.ReadLine()))

iCount++;



Console.Write("请回答差:");

if (i - j == int.Parse(Console.ReadLine()))

iCount++;



Console.Write("请回答积:");

if (i * j == int.Parse(Console.ReadLine()))

iCount++;








Console.Write("请回答商:");

if(Math.Abs((double)i/j-double.Parse(Console.ReadLine()))<0.0001)

iCount++;



Console.Write("请回答余数:");

if (i % j == int.Parse(Console.ReadLine()))

iCount++;



Console.WriteLine("\n你回答正确了" + iCount.ToString() + "个");



Console.Write("需要继续吗?若要继续,请按Y");

sContinue = Console.ReadLine();

} while (sContinue == "Y");



Console.ReadKey();

}







程序运行结果如图31所示。


图31和、差、积、商和取余运算


上述求商时,注意写法。对上例,i/j的结果是整数,故需要写为(double)i/j。
上述程序的逻辑是: 输入Y继续,输入任意其他内容都将退出,你能改造程序,使其输入Y继续,输入N退出,输入其他则提醒用户重新输入吗?











第4章
面向对象基础







4.1实验目的及要求
(1) 掌握面向对象的特性: 封装、继承、多态。
(2) 掌握类成员: 字段、属性、方法、构造函数、委托等。
(3) 理解public、private、static等关键字。
(4) 理解接口、抽象方法、虚方法、重载等术语含义。
4.2实 验 内 容
(1) 实现一个简单的数学运算类SimpleMath,要求如下。
定义2个属性,分别代表两个操作数。
定义4个普通的无参方法,分别完成加减乘除运算。
为类编写静态方法,分别完成两个数的加减乘除运算。
需要的话可以自行选择构造函数或者重载。
分析: 该题比较简单,主要练习了属性、方法、构造函数的使用。参考代码如下: 



class SimpleMath

{

private double x;

public double X

{

get { return x; }

set { x = value; }

}



private double y;

public double Y

{

get { return y; }

set { y = value; }

}

public SimpleMath(double x,double y)






{

this.x = x;

this.y = y;

}



public double Add()

{

return x + y;

}



public double Sub()

{

return x - y;

}



public double Mul()

{

return x * y;

}



public double Div()

{

return x / y;

}





public static double Add(double x, double y)

{

return x + y;

}



public static double Sub(double x, double y)

{

return x - y;

}



public static double Mul(double x, double y)

{

return x * y;

}



public static double Div(double x, double y)

{

return x / y;

}

}






调用代码如下: 



static void Main(string[] args)

{

Console.WriteLine("输入两个数:");

double x = double.Parse(Console.ReadLine());

double y = double.Parse(Console.ReadLine());

SimpleMath math = new SimpleMath(x,y);

Console.WriteLine("{0}+{1}={2}",x,y,math.Add());

Console.WriteLine("{0}-{1}={2}", x, y, math.Sub());

Console.WriteLine("{0}*{1}={2}", x, y, math.Mul());

Console.WriteLine("{0}/{1}={2}", x, y, math.Div());



Console.WriteLine("{0}+{1}={2}", x, y, SimpleMath.Add(x,y));

Console.WriteLine("{0}-{1}={2}", x, y, SimpleMath.Sub(x, y));

Console.WriteLine("{0}*{1}={2}", x, y, SimpleMath.Mul(x, y));

Console.WriteLine("{0}/{1}={2}", x, y, SimpleMath.Div(x, y));



Console.Read();

}







图41简单的数学
运算类


程序运行效果如图41所示。
(2) 实现一个矩形类Rectangle,创建其实例并使用,要求如下。
字段成员为: Length,Width; 且可供实例访问。
3个构造函数,其中第一个无参构造函数将长宽字段成员赋0,第二个有参构造函数根据用户实例化传入的参数给长宽赋值; 第三个构造函数传入面积值。
3个方法: 分别判断该矩形是否为正方形、计算周长、计算面积。
用户采用第三个构造函数时,根据传入的面积参数,分解出一组长宽最接近的值。
假设上述值都为整数。
分析: 该题目也比较简单,涉及的知识点有: 字段、构造函数、运算符、整数分解、循环语句等,当然读者可以在上述基础上增加属性等。参考代码如下: 



class Rectangle

{

public int Length;

public int Width;



//构造函数

//将长宽字段赋值 0

public Rectangle()

{

Length = 0;

Width = 0;

}

//有参构造函数,根据用户实例化传入的参数给长宽赋值;






public Rectangle(int length, int width)

{

this.Length = length;

this.Width = width;

}

//接受传入面积以及分解面积

public Rectangle(int area)

{

int i, min;

min = area;

//分解面积,得到长和宽

for (i = Convert.ToInt32(Math.Sqrt(area)); i >= 1; i--)

{

if (area % i == 0)

{

Width = i;

Length = area / Width;

break;

}

}

}



// 方法1 判断矩形是否为正方形

public bool IsSquare()

{

if (Length == Width)

return true;

else

return false;

}

//方法2  计算周长

public int Perimeter()

{

int perimeter = 2 * (Length + Width);

return perimeter;

}

//方法3  计算面积

public int Area()

{

int area = Length * Width;

return area;

}

}




演示调用代码如下: 



static void Main(string[] args)

{

int iLength = 0, iWidth = 0, iPerimeter, iArea;







Console.Write("请输入矩形的长:");

iLength = Convert.ToInt32(Console.ReadLine());



Console.Write("请输入矩形的宽:");

iWidth = Convert.ToInt32(Console.ReadLine());



Rectangle rect = new Rectangle(iLength, iWidth);

if (rect.IsSquare() == true)

Console.WriteLine("是正方形");



iPerimeter = rect.Perimeter();

Console.WriteLine("矩形的周长为:" + iPerimeter);

iArea = rect.Area();

Console.WriteLine("矩形的面积为:" + iArea);



Console.Write("请输入指定矩形的面积:");

iArea = Convert.ToInt32(Console.ReadLine());



Rectangle rect2 = new Rectangle(iArea);

iLength = rect2.Length;

iWidth = rect2.Width;

Console.Write("分解后得到的长和宽分别为:" + iLength + "和" + iWidth);



Console.ReadLine();

}






图42矩形类演示

程序运行结果如图42所示。
(3) 编写一个类Cal,要求如下。
此类具有2个属性OpNum1,OpNum2,一个无参虚方法CalExpression,用于计算两数的结果。
一个接口ICalIt,其中包含一个方法CalResult,用于计算两数的结果。
编写四个类,均继承于Cal,分别完成两个操作数的四则运算。
编写一个类CalOprs,包含一个方法GetOpr,方法返回类型为Cal,参数为加减乘除之一。
编写Main中的测试代码部分。
分析: 此题目涉及的知识点有: 虚方法、接口、继承、属性、多态等。由于虚方法和接口的功能都是实现两个操作数的相应的数值运算,故此处仅以接口为例来实现,使用虚方法的方式请读者自行实现。以下将分别介绍各个类或者接口的代码。
接口定义代码如下: 



//ICalIt接口

interface ICalIt

{

double CalResult();

}




Cal类代码如下: 



//Cal类该类实现了接口

class Cal : ICalIt

{

private double opNum1;

private double opNum2;



public double OpNum1

{

get { return opNum1; }

set { opNum1 = value; }

}



public double OpNum2

{

get { return opNum2; }

set { opNum2 = value; }

}



public Cal()

{

this.opNum1 = 0;

this.opNum2 = 0;

}

public Cal(double opNum1, double opNum2)

{

this.opNum1 = opNum1;

this.opNum2 = opNum2;

}

//该方法定义为虚方法,将在子类中重写来实现各种运算

public virtual double CalResult()

{

return 0;

}

}




下面是实现四则运算的4个类的代码。



//实现加法的类

class CalAdd : Cal

{

public CalAdd(): base()

{

}

public CalAdd(double opNum1, double opNum2): base(opNum1, opNum2)

{

}

//重写基类方法







public override double CalResult()

{

return this.OpNum1 + this.OpNum2;

}

}



//实现减法的类

class CalSub : Cal

{

public CalSub(): base()

{

}



public CalSub(double opNum1, double opNum2): base(opNum1, opNum2) { }

//重写基类方法

public override double CalResult()

{

return this.OpNum1 - this.OpNum2;

}

}



//实现乘法的类

class CalMul : Cal

{

public CalMul(): base()

{

}

public CalMul(double opNum1, double opNum2): base(opNum1, opNum2) { }

//重写基类方法

public override double CalResult()

{

return this.OpNum1 * this.OpNum2;

}

}



//实现除法的类

class CalDiv : Cal

{

public CalDiv(): base()

{

}

public CalDiv(double opNum1, double opNum2): base(opNum1, opNum2) { }

//重写基类方法

public override double CalResult()

{

if (this.OpNum2 == 0)

{

throw new Exception("除数不能为零.");

}

return this.OpNum1 / this.OpNum2;

}

}




以下是CalOprs类,该类根据传入运算符,实例化相应的运算类,代码如下: 



class CalOprs

{

public static Cal GetOpr(string oprsType)

{

if (oprsType == "+")

return new CalAdd();

else if (oprsType == "-")

return new CalSub();

else if (oprsType == "*")

return new CalMul();

else if (oprsType == "/")

return new CalDiv();

else

return null;

}

}




最后是供演示调用的类,代码如下: 



static void Main(string[] args)

{

Console.WriteLine("运算方式:\t加法:+\t减法:-\t乘法:*\t除法:/");

string op = Console.ReadLine();



Cal cal = null;

switch (op)

{

case "+":

cal = CalOprs.GetOpr("+");

break;

case "-":

cal = CalOprs.GetOpr("-");

break;

case "*":

cal = CalOprs.GetOpr("*");

break;

case "/":

cal = CalOprs.GetOpr("/");

break;

default:

break;

}



Console.WriteLine("请输入两个操作数,每次以Enter键结束输入");

cal.OpNum1 = double.Parse(Console.ReadLine());

cal.OpNum2 = double.Parse(Console.ReadLine());







Console.WriteLine("{0}{1}{2}={3}", cal.OpNum1, op, cal.OpNum2, cal.CalResult());



Console.ReadKey();

}







图43多态、继承等综合演示


程序运行效果如图43所示。
此例也使用了一种知名的设计模式,有兴趣的读者自行钻研,此处不再展开。
(4) 编写一个定时触发的事件及所有相关演示程序。详细要求如下: 
编写一个自定义类DataEventArgs,继承于EventArgs,用于在事件处理中传递数据,所需传递数据包含当前时间、当前第几次触发这两项信息。
编写一个事件触发类,其中含一个方法Fire(int i),根据传入的i的次数决定触发多少次事件。
编写一个事件接收类,该类中要求完成对多播的演示(即要求有多个处理过程绑定到上述事件),在事件处理过程中输出通过自定义参数传递过来的数据信息。
定时触发的过程可以借助Thread.Sleep及循环来实现。
分析: 该题主要考查的是事件。下面分块给出代码并给予适当的注释。
首先看DataEventArgs类的代码,如下: 



public class DataEventArgs:EventArgs

{

private DateTime dt;

private int count;

public DateTime TrigTime

{

get

{

return dt;

}

}

public int Count

{

get

{

return count;

}

}



public DataEventArgs() 

{ 	






}

public DataEventArgs(DateTime dt, int count) 

{

this.dt = dt;

this.count = count;

}

}




事件委托及事件触发类代码如下: 



public delegate void MyDelegate(object sender,EventArgs e);//事件委托



//触发事件类

public class EventTrigger

{

public event MyDelegate MyDelegateEvent;

public void Fire(int max)

{

//按照指定的次数来触发事件,每次触发的时间间隔为1000ms

for (int i = 0; i < max; i++)

{

if (MyDelegateEvent != null)

{

MyDelegateEvent(this, new DataEventArgs(DateTime.Now, i));

Thread.Sleep(1000);

}

}

}

}





事件接收类代码如下: 



// 事件接收类

public class EventSubscription

{

public void SubscriptionEvent()

{

EventTrigger et = new EventTrigger();		

et.MyDelegateEvent += new MyDelegate(eventTrig_MyDelegateEvent);//订阅

et.Fire(10); //触发10次

}

//从DataEventArgs参数e中获取第几次触发和各次触发的时间

void eventTrig_MyDelegateEvent(object sender, DataEventArgs e)

{

Console.WriteLine("事件于第{0}次触发,触发时间为:{1}", e.Count, e.TrigTime.ToString());

}

}




演示调用代码如下: 



static void Main(string[] args)

{

EventSubscription es = new EventSubscription();

es.SubscriptionEvent();

}




程序执行效果如图44所示。



图44定时触发的事件