当前位置: 首页 > article >正文

C#开发实例2—模拟考试

实例练习目的主要是为了体会编程思想,理解高内聚、低耦合,掌握编程思维逻辑的大招,告别垃圾代码,重点体会编程之美…

目录

  • 1. 软件实现的功能有哪些?(UI如何设计)
  • 2.数据在哪里获取?
  • 3.对象有哪些,它们之间的关系是什么?
  • 4.如何设计类(列出属性<成员>、方法<功能>)?
  • 5.代码实现
  • 6.软件效果
  • 7.思路如下所示(重点体会思路,思路清晰代码就成了):
  • END

开发一个项目之前,切记不要打开程序就写代码,首先要做的就是分析项目,从项目的架构开始思考,软件要实现什么功能(思考UI界面布局);数据从哪里获取?(数据库、文本文件、通讯接口…);重点思考项目对象、功能有哪些?(对象的属性<成员>、方法<功能>,之间的关系…),以此项目为例,思维导图如下:


1. 软件实现的功能有哪些?(UI如何设计)

答: 用一个主界面实现,有标题栏(项目名称及关闭按钮)、菜单栏(上一题、下一题、提交按钮)、内容显示题目,选项以勾选的方式答题,最后提交得出总分;

2.数据在哪里获取?

答: 文本文件(是否可靠,避免用户更改源文件,进一步优化<序列化保存文件后反序列化读取>—用到的技能:文本文件操作<后续总结概括>)

3.对象有哪些,它们之间的关系是什么?

答: 软件运行强相关的对象有试卷、试题、答案(正确答案、错误答案);一张试卷中若干试题(一对多),试题在试卷中以集合的方式存在;试题的答案唯一(一对一),答案在试题中以对象属性的形式存在;

4.如何设计类(列出属性<成员>、方法<功能>)?

答: 窗体加载试卷对象(试题加载(答案));从最底层答案类开始设计:


5.代码实现

  1. 【答案类】
  • 属性:所选答案、正确答案;
/// <summary>
/// 答案类(属性<成员变量>:所选答案、正确答案)
/// </summary>
[Serializable]  //实体类需序列化保存
public class Answer
{
    public string SelectAnswer { get; set; } = string.Empty;
    public string RightAnswer { get; set; } = string.Empty;
}
  1. 【试题类】
  • 属性:题干、选项、答案(对象属性<需在类的构造方法初始化>);
/// <summary>
/// 试题类(属性:题干、答案<对象属性-构造函数初始化>)
/// </summary>
[Serializable]
public class Question
{
    public Question()  //构造函数初始化
    {
        QueAnswer = new Answer();
    }
    public string Title { get; set; } = string.Empty;
    public string DescriptionA { get; set; } = string.Empty;
    public string DescriptionB { get; set; } = string.Empty;
    public string DescriptionC { get; set; } = string.Empty;
    public string DescriptionD { get; set; } = string.Empty;
    public Answer QueAnswer { get; set; }  //答案为对象属性
}
  1. 【试卷类】
  • 属性:试题集合List;
  • 方法:计算总分、读取文本(抽取试题);
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace WindowsFormsApp_试卷抽题.Models
{
    /// <summary>
    /// 试卷类(属性:试题集合、  方法:抽题、分数)
    /// </summary>
    public class Paper
    {
        //构造函数初始化(对象属性)
        public Paper()
        {
            questions = new List<Question>();
        }
        //字段:试题对象集合
        private List<Question> questions;
        //属性:只读
        public List<Question> Questions { get { return this.questions; } }

        //方法:分数【遍历试题选择的答案与正确答案相等即可得分】
        public int Grade()
        {
            int score = 0;
            foreach (Question item in questions)
            {
                if (item.QueAnswer.SelectAnswer == string.Empty) continue;
                if (item.QueAnswer.SelectAnswer.Equals(item.QueAnswer.RightAnswer)) score += 5;
            }
            return score;
        }

        //方法:抽题:【初始化(1.读文件 2.保存为序列化文件 3.打开序列化文件)】
        //读文本文件
        public void OpenPaper1()
        {
            FileStream fs = new FileStream("questions.txt", FileMode.Open);
            StreamReader sr = new StreamReader(fs, Encoding.Default); //注意默认编码方法
            string txtPaper = sr.ReadToEnd();  //读取全部内容到txtPaper
            string[] txtQuestions = txtPaper.Trim().Split('&');  //分割内容保存到试题数组;注意去空格
            string[] txtQuestion = null; //保存一道题到txtQuestion
            foreach (string item in txtQuestions)
            {
                txtQuestion = item.Trim().Split('\r');
                this.questions.Add(new Question
                {
                    Title = txtQuestion[0].Trim(),
                    DescriptionA = txtQuestion[1].Trim(),
                    DescriptionB = txtQuestion[2].Trim(),
                    DescriptionC = txtQuestion[3].Trim(),
                    DescriptionD = txtQuestion[4].Trim(),
                    QueAnswer = new Answer { RightAnswer = txtQuestion[5].Trim() }
                });
            }
            sr.Close();
            fs.Close();
        }

        //保存为序列化文件
        public void SavePaper()
        {
            FileStream fs = new FileStream("Paper.obj", FileMode.Create); //创建文件
            BinaryFormatter bf = new BinaryFormatter();  //序列化器
            bf.Serialize(fs, this.questions);  //序列化对象
            fs.Close();
        }

        //打开序列化文件【保存文件后用此方法将独到的数据传递到试题集合中即可】
        public void OpenPaper2()
        {
            FileStream fs = new FileStream("Paper.obj", FileMode.Open); //打开文件
            BinaryFormatter bf = new BinaryFormatter(); //序列化器
            this.questions = (List<Question>)bf.Deserialize(fs);  //反序列化到对象
            fs.Close();
        }
    }
}

3.【边界类】

  • 属性:试卷对象;
  • 方法:显示题目、保存答案、重置答案;
/// <summary>
/// 边界类:试卷对象、题序  方法:显示题目、保存答案、重置答案
/// </summary>
public partial class FrmMain : Form
{
    //窗口初始化
    public FrmMain()
    {
        InitializeComponent();
        this.palCover.Visible = true;
        this.lblView.Text = "试卷密封中,等待抽题......";
    }

    //试卷对象、题序号
    private Paper Paper = new Paper();
    private int QuestionIndex = 0;

    //开始抽题
    private void btnStart_Click(object sender, EventArgs e)
    {
        this.palCover.Visible = false;
        //显示第一题
        this.Paper.OpenPaper1();  //打开txt文件
        //this.Paper.SavePaper();  //保存文序列化文件
        //this.Paper.OpenPaper2();   //反序列化打开试卷
        ShowPaper();

    }

    //提交试卷
    private void btnSubmit_Click(object sender, EventArgs e)
    {
        this.palCover.Visible = true;
        //保存答案并判断
        SaveAnswer();
        int score = this.Paper.Grade();
        //显示成绩
        this.lblView.Text = $"您的得分是: {score}  分";
    }

    //上一题
    private void btnUp_Click(object sender, EventArgs e)
    {
        if (QuestionIndex == 0) return;
        else
        {
            SaveAnswer();
            QuestionIndex--;
            ResetAnswer();
            ShowPaper();
        }
    }

    //下一题
    private void btnDown_Click(object sender, EventArgs e)
    {
        if (QuestionIndex == Paper.Questions.Count - 1) return;
        else
        {
            SaveAnswer();
            QuestionIndex++;
            ResetAnswer();
            ShowPaper();
        }
    }

    //显示试题
    public void ShowPaper()
    {
        this.lblTiltle.Text = this.Paper.Questions[this.QuestionIndex].Title;
        this.lblA.Text = this.Paper.Questions[this.QuestionIndex].DescriptionA;
        this.lblB.Text = this.Paper.Questions[this.QuestionIndex].DescriptionB;
        this.lblC.Text = this.Paper.Questions[this.QuestionIndex].DescriptionC;
        this.lblD.Text = this.Paper.Questions[this.QuestionIndex].DescriptionD;
    }

    //保存答案
    public void SaveAnswer()
    {
        string selecetAnswer = string.Empty;
        if (this.ckbA.Checked) selecetAnswer += "A";
        if (this.ckbB.Checked) selecetAnswer += "B";
        if (this.ckbC.Checked) selecetAnswer += "C";
        if (this.ckbD.Checked) selecetAnswer += "D";
        this.Paper.Questions[QuestionIndex].QueAnswer.SelectAnswer = selecetAnswer;
        
    }

    //重置答案
    public void ResetAnswer()
    {
        this.ckbA.Checked = this.Paper.Questions[this.QuestionIndex].QueAnswer.SelectAnswer.Contains("A");
        this.ckbB.Checked = this.Paper.Questions[this.QuestionIndex].QueAnswer.SelectAnswer.Contains("B");
        this.ckbC.Checked = this.Paper.Questions[this.QuestionIndex].QueAnswer.SelectAnswer.Contains("C");
        this.ckbD.Checked = this.Paper.Questions[this.QuestionIndex].QueAnswer.SelectAnswer.Contains("D");
    }

    //退出
    private void btnClose_Click(object sender, EventArgs e)
    {
        this.Close();
    }
}

6.软件效果


7.思路如下所示(重点体会思路,思路清晰代码就成了):


后续添加源码下载链接

END


http://www.kler.cn/a/455642.html

相关文章:

  • nginx-nginx的缓存集成
  • WPF使用资源定义和样式资源,解耦视图与逻辑(较多样式重复的时候使用)
  • 新手SEO指南如何快速入门与提升网站排名
  • 基于Debian的Linux发行版的包管理工具
  • 部分背包问题
  • Docker【初识Docker】
  • Jsonlizer,一个把C++各类数据转成 Json 结构体的玩意儿
  • asp.net core系统记录当前在线人数
  • 组建基于IPV6的网络
  • 更新本地项目到最新git版本脚本
  • 每天40分玩转Django:Django Email
  • 微服务网关路由
  • node.js高级用法
  • LeetCode -Hot100 - 56. 合并区间
  • 【centos8 镜像修改】centos8 镜像修改阿里云
  • c++编译过程初识
  • 【Java 代码审计入门-03】XSS 漏洞原理与实际案例介绍
  • MFC扩展库BCGControlBar Pro v36.0 - 可视化管理器等全新升级
  • Vision Transformer (ViT) 论文的第二句话
  • 踏踏实实练SQLday2-3连续12345
  • 机器学习2-NumPy
  • 华为 IPD,究竟有什么特点?(二)
  • scala图书借阅系统完整代码
  • 基于Docker的ETCD分布式集群
  • SQL-leetcode-180. 连续出现的数字
  • ctfshow web 笔记