标准开头
Items | Answers |
---|---|
GIT地址 | GIT |
GIT用户名 | homlex |
学号后5位 | 62618 |
博客地址 | 博客主页 |
作业地址 | 作业地址 |
一、从其他用户克隆仓库到本地
过程 | 操作记录 |
---|---|
一、 fork | |
二、克隆 | |
三、配置安装 | |
四、完成启动 |
二、创建项目并编码。
① 创建项目:
创建一个C#.NET 项目,ConsoleApp, 改名为Calculator。
② 设计思路:
1、设计一个
MyRandom
类, 用于产生随即运算符和随机操作数。(为了方便计算,将这里的数字和符号统统设为string
型。)2、设计一个
Formular
类,用于组合这些随机数和随机符号和随机数,并得到其结果,包含一个核心方法:得到完整算式的一个集合,如:{"5+6×3-1 = 22", "3+2-5×0=5", "8×2-6÷2=13"}3、设计
WriteFile
类,一个save(string, List<string>)
方法来将表达式存为txt为文件。4、设计
Executioner
类,配合栈结构,根据具体操作符来返回对应的结果。5、设计计算加减乘除的4个类,返回对应结果。其他细节不做过多介绍。
完整代码在GitHub上。
接下来是编码时间。
③ 一番"Code And Fix"之后的初代成品:
代码在末尾~ ---> 前往
④ 运行结果:
三、单元测试
① 右键-->创建单元测试--> OK
先对Executioner类进行测试。
② 运行结果:可以看到对Executioner的Calc方法测试结果全部通过
接着对Formular类的GetFullExpressions方法测试:
③ 断点调试(在Formular的GetResult方法中设置断点,然后启动调试)
程序在断点处停住。单步执行几下后可以在下方观察局部变量的变化等等等其他调试信息。
④ 性能查看.
先将要产生的四则运算个数以硬编码的形式改为100万,再
ALT+F2
,勾选CPU Usage
, 下方点击开始。1分13秒后生成了测试报告。
可以看到Formular对CPU的占用率最大,主要是因为这个类既要产生表达式还要获得结果,因此可以看出在此程序运行过程中其占比几乎达到100%。而其他的方法偏低。 GetRandomNum比GetRandomOpt多大概10%,这是符合预期的,因为每一次产生数据,前者都要比后者多调用一次。
生成详细报告:点击这里:
他会生成一个
vspx
文件,我们可以看看程序运行的一些细节情况。从整体看来,对CPU的消耗情况比较稳定。随机选取了三个时间点:可以看到使用率基本上平衡在12%.
之后点进占用率最大的GetFullExpressions方法之后可以看到它的一些细节情况。
四、回归测试
回归测试即是对重构之后的代码再次测试,可以防止代码更改后出现新的bug的情况。此次依然是对Executioner
类进行测试,结果如下
五、克隆以及上传
① 克隆:
上面已经演示过了,
这里就只记录了代码上传的过程。② 上传:
来到目录下,右键 打开gitbash
③ 输入git指令
主要执行的
git
命令如下:$ git config --global user.email "xxxxxxx@qq.com" $ git config --global user.name "homlex" $ git init #此次没有用到 $ git add . $ git commit -m "Generate random formulas" $ git remote add origin git@github.com:homlex/AchaoCalculator.git $ git push -u origin master
④ 上传成功
六、遇到的问题&解决
① 安装于配置问题 :
由于之前安装配置过一次,所以这次的配置比较熟悉,一切顺利,没有问题。
② 代码问题:
1、在同一次的运行中,产生的随机数全部都一样
初始化随机种子,将
Random random = new Random();
改为
Random random = new Random(Guid.NewGuid().GetHashCode());
2、计算结果问题。
在计算过程进行到特定阶段时,将用到的数据加以处理。(我这里是将栈逆转)
③ 测试问题:
1、没有遇到特别的问题,就是最开始不知道怎么写这个单元测试,不过后来通过百度解决了。
④ git 问题:
1、运行
git add
时报错如下:error: open(".vs/Calculator/v15/Server/sqlite3/db.lock"): Permission denied error: unable to index file '.vs/Calculator/v15/Server/sqlite3/db.lock' fatal: adding files failed
原因:db.lock文件拒绝访问
在当前目录下创建
.gitignore
文件,用记事本编辑:/.vs
保存,再次
git add
. 原理:既然拒绝访问那就不要add它了吧~2、其他关于git命令问题我参考了这篇文章:git的初次使用。
七、总结
- 以上就是本次作业的全过程,通过本次实操,我熟悉了git的使用,掌握了单元测试的方法,了解了如何查看程序性能,从性能查看结果分析出了后期对代码的优化方向。
- 熟悉硬知识很重要。在求值的时候使用了dijstra双栈的办法,但是由于对数据结构的知识记忆不是很牢,所以在求值这里花了很多时间。
Visual Studio
用起来很舒服,在测试程序的时候将测试结果变得可视化,更加方便了Coder对代码的管控和了解,对代码的优化也起了不小的帮助。- PS:GitHub网站是真的慢。git命令使用起来很方便也很快捷。?
附:主要代码
// Program.cs
using System;
using System.IO;
namespace Calculator
{
class Program
{
static void Main(string[] args)
{
int lines = 0;
try
{
lines = int.Parse(args[0]);
//lines = 100;
if (lines <=0)
{
Console.WriteLine("\n 仅支持 `$ Calculator <一个正整数>` 的形式!"); return;
}
string path = Directory.GetCurrentDirectory() + "\\subject.txt";
WriteFile.save(path, new Formular(1, 8).GetFullExpressions(lines));
System.Console.WriteLine("\n 已保存至 " + Directory.GetCurrentDirectory() + "\\subject.txt");
}
catch (Exception)
{
Console.WriteLine("\n 仅支持 `$ Calculator <一个正整数>` 的形式!"); return;
}
return;
}
}
}
// Formulary.cs
using System;
using System.Collections.Generic;
namespace Calculator
{
public class Formular
{
private int min, max;//操作数范围
public Formular(int min, int max)
{
this.min = min;
this.max = max;
}
//表达式
private string[] expression;
/// <summary>
/// 初始化,生成一个数学表达式
/// </summary>
/// <param name="min">操作数最小值</param>
/// <param name="max">操作数最大值</param>
private void Init(int min, int max)
{
int operCount = new Random(Guid.NewGuid().GetHashCode()).Next(2, 4);
expression = new string[operCount * 2 + 1];
for (int i = 0; i < expression.Length; i++)
{
expression[i] = (i % 2 == 0) ? MyRandom.GetRandomNum(min, max) : MyRandom.GetRandomOpt();
}
}
/// <summary>
/// 得到多个完整算式,去除负数结果
/// </summary>
/// <returns></returns>
public List<string> GetFullExpressions(int lines)
{
List<string> list = new List<string>();
for (int i = 0; i < lines; i++)
{
Init(this.min, this.max);
string temp = "";
foreach (var item in this.expression)
{
temp += item;
}
string res = GetResult();
if (int.Parse(res) < 0)
{
i--;
}
else
{
list.Add(temp + "=" + GetResult());
}
}
return list;
}
/// <summary>
/// 计算表达式结果
/// </summary>
/// <returns></returns>
private string GetResult()
{
Stack<string> vals = new Stack<string>();
Stack<string> opts = new Stack<string>();
for(int i = 0; i < expression.Length; i++)
{
if ("+-".Contains(expression[i]))
{
opts.Push(expression[i]);
}
else if("×÷".Contains(expression[i]))
{
vals.Push(new Executioner(expression[i]).Calc(vals.Pop(), expression[i + 1]));
i++;
}
else
{
vals.Push(expression[i]);
}
}
//栈内只剩下加减法,为避免连续减法出错,于是将两者逆序便于依次计算
vals = vals.Count == 0 ? vals : Reverse(vals);
opts = opts.Count == 0 ? opts : Reverse(opts);
while (0 != opts.Count)
{
vals.Push(new Executioner(opts.Pop()).Calc(vals.Pop(), vals.Pop()));
}
return vals.Pop();
}
/// <summary>
/// 反转栈
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
private Stack<string> Reverse(Stack<string> param)
{
Stack<string> result = new Stack<string>();
while (param.Count>0)
{
result.Push(param.Pop());
}
return result;
}
}
}
// Executioner.cs
namespace Calculator
{
public class Executioner : Evaluate
{
private Evaluate evaluate;
public Executioner(string opt)
{
switch (opt)
{
case "+": this.evaluate = new Add(); break;
case "-": this.evaluate = new Sub(); break;
case "×": this.evaluate = new Mul(); break;
case "÷": this.evaluate = new Div(); break;
}
}
public string Calc(string num1, string num2)
{
return this.evaluate.Calc(num1, num2);
}
}
}