熟练使用工具
|
:-😐:-:
Git地址|https://github.com/Kowaine
Git用户名|Kowaine
学号后五位|62127
博客地址|https://www.cnblogs.com/Kowaine/
作业链接|https://www.cnblogs.com/harry240/p/11515697.html
目录
VS环境配置
由于环境早已配置好,此处只作简要说明打开vs安装程序后,勾选C#开发所需组件,一路点击继续,即能安装完成(可能需要重启)
安装完成后,创建一个helloworld程序,确定能否运行 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918172645989-1631456561.png)
正常运行 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918172807079-237255116.png)
克隆Github项目
在cmd或者gitbash中输入克隆命令(cmd中需要配置环境变量)git clone https://github.com/Kowaine/AchaoCalculator.git
![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918173928868-843194693.png)
克隆完成后的文件夹 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918174111138-229839435.png)
至此,项目的克隆就完成了 然后,进入克隆的项目文件夹中,新建一个以自己github用户名相同的文件夹 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918175457782-1650131926.png)
之后,在VS中以这个新建的文件夹为根目录创建一个控制台项目 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918180731869-972801919.png) ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190918180952232-1077510375.png)
至此,项目开发的准备就完成了
编写基础程序
需求整理
1.接收一个整数参数 n,随机产生 n 道加减乘除(分别使用符号+-*/来表示)练习题。 2.数字取值范围[0, 100],运算符2个或3个。 3.运算结果为整数 4 结果以“subject.txt”的文件格式输出设计思路
设计的难点主要在于结果必须为整数这一点上,很容易发现的是,只有除法可能产生小数。因此,整体设计的重点就在于如何让除法不产生小数结果上。 经过思考,我发现,由于除号和乘号在没有括号的四则运算中有着最高的优先级,而其他运算又不会产生小数,所以只要保证除号前后两个数的运算不产生小数即可。最终,具体设计思路如下: 1.生成两到三个运算符。 2.从后往前生成运算数,除号前的数用除号后的数乘以一个随机数得到 3.运用堆栈计算并返回完整字符串 4.重复以上步骤n次后,将全部计算式写入文件
具体代码(初版)
class Program
{
static void Main(string[] args)
{
Console.Write("Please input the number of problems: ");
int n = int.Parse(Console.ReadLine());
string[] problems = new string[n];
for (int i = 0; i < n; ++i)
{
//生成一组数据
ArrayList data = generateData();
int result = Calculate((Stack)(((Stack)data[0]).Clone()), (Stack)(((Stack)data[1]).Clone()));
if (result < 0)
{
i--;
continue;
}
problems[i] = toString((Stack)(((Stack)data[0]).Clone()), (Stack)(((Stack)data[1]).Clone()), result);
}
writeToFile(problems);
}
/// <summary>
/// 操作符基类
/// </summary>
public interface Operator
{
//计算
int doCal(int x, int y);
string toString();
int getPriority();
}
public class Add : Operator
{
private int priority;
public Add()
{
priority = 0;
}
public int doCal(int x, int y)
{
return x + y;
}
public string toString()
{
return "+";
}
public int getPriority()
{
return priority;
}
}
public class Sub : Operator
{
private int priority;
public Sub()
{
priority = 1;
}
public int doCal(int x, int y)
{
return x - y;
}
public string toString()
{
return "-";
}
public int getPriority()
{
return priority;
}
}
public class Mul : Operator
{
private int priority;
public Mul()
{
priority = 2;
}
public int doCal(int x, int y)
{
return x * y;
}
public string toString()
{
return "*";
}
public int getPriority()
{
return priority;
}
}
public class Div : Operator
{
private int priority;
public Div()
{
priority = 3;
}
public int doCal(int x, int y)
{
return x / y;
}
public string toString()
{
return "/";
}
public int getPriority()
{
return priority;
}
}
/// <summary>
/// 生成运算符的工厂类
/// </summary>
public class OperatorFactory
{
private Random random = new Random();
/// <summary>
/// 生成一个随机的操作符类
/// </summary>
/// <returns>生成的操作符类</returns>
public Operator randOprator()
{
int index = random.Next(0, 4);
switch(index)
{
case 0:
return new Add();
case 1:
return new Sub();
case 2:
return new Mul();
case 3:
return new Div();
default:
return null;
}
}
}
/// <summary>
/// 产生随机数的工厂类
/// </summary>
public class NumberFactory
{
private Random random = new Random();
public int randNumber(int minNum, int maxNum)
{
return random.Next(minNum, maxNum + 1);
}
}
/// <summary>
/// 计算
/// </summary>
/// <param name="ops">操作符的反向栈</param>
/// <param name="nums">操作数的反向栈</param>
/// <returns>最终结果</returns>
public static int Calculate(Stack ops, Stack nums)
{
// 生成两个栈供使用
Stack opStack = new Stack();
Stack numStack = new Stack();
// 开始入栈计算
numStack.Push(nums.Pop());
while (nums.Count != 0)
{
numStack.Push(nums.Pop());
Operator thisOp = (Operator)ops.Pop();
if (ops.Count != 0)
{
Operator nextOp = (Operator)ops.Peek();
// 比较优先级,若当前运算符优先级大于等于下一个运算符,则先运算
if (thisOp.getPriority() >= nextOp.getPriority())
{
int x2 = (int)numStack.Pop();
int x1 = (int)numStack.Pop();
int result = thisOp.doCal(x1, x2);
numStack.Push(result);
}
else
{
opStack.Push(thisOp);
}
}
else
{
opStack.Push(thisOp);
}
}
// 确保运算完全完成
while (opStack.Count != 0)
{
int x2 = (int)numStack.Pop();
int x1 = (int)numStack.Pop();
numStack.Push(((Operator)opStack.Pop()).doCal(x1, x2));
}
return (int)numStack.Pop();
}
/// <summary>
/// 生成一组计算所需数据
/// </summary>
/// <returns>ArrayList(操作符反向栈, 操作数反向栈)</returns>
public static ArrayList generateData()
{
// 创建工厂
OperatorFactory operatorFactory = new OperatorFactory();
NumberFactory numberFactory = new NumberFactory();
// 操作符数量
Random random = new Random();
// 生成操作符
int opCount = random.Next(2, 4);
ArrayList opList = new ArrayList();
for (int i = 0; i < opCount; ++i)
{
opList.Add(operatorFactory.randOprator());
}
opList.Reverse();
// 根据操作符数量生成操作数
ArrayList numList = new ArrayList();
numList.Add(numberFactory.randNumber(1, 99));
int divCount = 0;
for (int i = 0; i < opCount; ++i)
{
string nextOp;
if (i == opCount - 1)
{
nextOp = "";
}
else
{
nextOp = ((Operator)opList[i + 1]).toString();
}
if (((Operator)opList[i]).toString() == "/" && nextOp != "/")
{
// 在连续除号的最后一个生成数字
int[] numArray = new int[divCount + 1];
numArray[divCount] = 101;
while (numArray[divCount] > 99)
{
numList[i - divCount] = numberFactory.randNumber(1, 10);
int lastNum = (int)numList[i-divCount];
int fistNum = lastNum;
//(100 / lastNum) >= 3 ? (100 / lastNum) : 3
int n = numberFactory.randNumber(2, (99 / lastNum) >= 3 ? (99 / lastNum) : 3);
numArray[0] = n * lastNum;
for (int j = 1; j < divCount + 1; ++j)
{
lastNum = numArray[j - 1];
n = numberFactory.randNumber(2, (99 / lastNum) >= 3 ? (99 / lastNum) : 3);
numArray[j] = n * lastNum * fistNum;
}
}
for (int j = 0; j < divCount + 1; ++j)
{
numList.Add(numArray[j]);
}
divCount = 0;
}
else if (((Operator)opList[i]).toString() == "/" && nextOp == "/")
{
divCount++;
}
else
{
numList.Add(numberFactory.randNumber(0, 99));
}
}
// 转化为栈
Stack opStack = new Stack();
for (int i = 0; i < opList.Count; ++i)
{
opStack.Push(opList[i]);
}
Stack numStack = new Stack();
for (int i = 0; i < numList.Count; ++i)
{
numStack.Push(numList[i]);
}
// 转化为一个List
ArrayList data = new ArrayList();
data.Add(opStack);
data.Add(numStack);
return data;
}
public static string toString(Stack opStack, Stack numStack, int result)
{
string resultString = "";
resultString += ((int)numStack.Pop()).ToString();
int count = opStack.Count;
for (int i = 0; i < count; i++)
{
resultString += ((Operator)opStack.Pop()).toString();
resultString += ((int)numStack.Pop()).ToString();
}
resultString += "=" + result.ToString();
return resultString;
}
public static void writeToFile(string[] problems)
{
string path = "subject.txt";
if (File.Exists(path))
{
File.Delete(path);
}
StreamWriter writer = new StreamWriter(path, true);
for (int i=0; i < problems.Length; ++i)
{
// 测试输出
//Console.WriteLine(problems[i] + "\n");
writer.WriteLine(problems[i]);
}
writer.Close();
writer.Dispose();
}
}
先用 "git add ."追踪新增的文件。然后用"git commit -am '代码初版' "提交代码 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919130003517-798241392.png)
使用"git status" 确定已经提交的数据,最后"git push" 提交到github(若电脑中安装了github桌面版,会跳出登录界面) ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919130548306-920460644.png)
登录到github,确认代码已经提交 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919130706280-2067204343.png)
单元测试的编写
首先,右键要测试的类或方法创建单元测试 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919151935816-1054339738.png)编写单元测试 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919153157536-834606222.png)
测试通过 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919153222926-1917723516.png)
本次实验主要目的在于工具的使用,故不在测试设计上多费功夫
VS调试的基本操作
断点
点击每行代码前可以添加断点,调试过程中程序将运行到此处暂停 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919154759945-261214416.png)调试
F11逐语句调试,F12逐过程调试,前者会进入函数调用单步执行,后者不会进入函数 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919155106072-757641251.png)变量监视
下方可以看到局部变量的变化,也可以右键自己添加监视 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919155211803-327853263.png) ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919155259068-959601663.png)回归测试
回归测试,指每次代码发生修改后,将代码进行过的单元测试再次运行,保证每次修改没有影响程序的稳定性。 此行为的效果主要体现在代码中,不便说明,不多赘述。效能分析
分析-性能探查器,勾选需要的项目后,点击开始运行分析 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919160802896-951000972.png)先更改部分代码以便测试,循环次数设置为1,000,000次 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919165715635-173676591.png)
分析中 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919193435133-1772775817.png)
分析完成 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919193458632-248719970.png)
更具体的数据 ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919193525095-1542409678.png) ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919193537015-2137032351.png)
发起分支合并请求
点击NewPullRequest ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919170907234-553604462.png)点击CreatePullRequest ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919190108776-623859300.png)
输入请求的title ![](https://img2018.cnblogs.com/blog/1784814/201909/1784814-20190919190506740-163887024.png)
至此,提交完成。