Множественного выбора анкета


Я новичок в C# и для моего назначения я должен изобрести несколько анкета местом, где студент может войти и пройти тест, посмотреть памятки и т. д. Я не очень обеспокоен GUI, но, скорее, структура моих занятий и код. Я буду использовать класс StudentController для взаимодействия с GUI. Это грубо, но вот мой код до сих пор:

Студент класс

public class Student : User
{
    private int finalMark;
    private List<int> answers;

    public Student()
    {
        answers = new List<int>();
    }

    /// <summary>
    /// Gets the final mark for the student
    /// </summary>
    public int GetFinalMark() => finalMark;

    /// <summary>
    /// Sets the final mark for the student
    /// </summary>
    public void SetFinalMark(int value) => finalMark = value;

    /// <summary>
    /// Fetches the answer the student chose for the indexed question
    /// </summary>
    /// <param name="index">The index of the question to retrieve the student's answer from</param>
    /// <returns>The index of the answer the user chose</returns>
    public int GetAnswer(int index) => answers[index];

    /// <summary>
    /// Sets the answer at the index's position
    /// </summary>
    /// <param name="index">The index to set the answer at</param>
    /// <param name="answer">The answer to set</param>
    public void SetAnswer(int index, int answer) => answers[index] = answer;

    /// <summary>
    /// Adds an answer to the student's list of answered questions
    /// </summary>
    /// <param name="answer">The answer to add to the list of answered questions</param>
    public void AddAnswer(int answer) => answers.Add(answer);
}

Множественный выбор вопрос

public class MultipleChoiceQuestion
{
    //  The question that is stated in the multiple choice question
    private string question;

    //  The list of possible answers to the question
    private string[] choices;

    //  The index of the correct answer, ie. choices[answer]
    private int answer;

    public MultipleChoiceQuestion()
    {
        choices = new string[4];
    }

    /// <summary>
    /// Gets and sets the question
    /// </summary>
    public string Question { get => question; set => question = value; }

    /// <summary>
    /// Gets the indexed question as a string
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public string GetChoices(int index) => choices[index];

    /// <summary>
    /// Sets the choice at the current index, eg. choice[0] = "Static void"
    /// </summary>
    /// <param name="index">The index of the choice</param>
    /// <param name="value">The choice to set</param>
    public void SetChoice(int index, string value) => choices[index] = value;

    /// <summary>
    /// Gets and sets the correct answer as an index
    /// </summary>
    public int Answer { get => answer; set => answer = value; }
}

Тестовый Класс

    public class Test
{
    private List<MultipleChoiceQuestion> question;

    public Test()
    {
        question = new List<MultipleChoiceQuestion>(); ;
    }

    /// <summary>
    /// Returns the question text at the given index of questions
    /// </summary>
    /// <param name="index">The index of the question to retrieve</param>
    /// <returns>A string of the question at the current index</returns>
    public string GetQuestionText(int index) => question[index].Question;


    public void SetQuestion(int index, string value) => question[index].SetChoice(index, value);

    /// <summary>
    /// Adds a new question to the list
    /// </summary>
    /// <param name="newQuestion">The question to add to the list</param>
    public void AddQuestion(MultipleChoiceQuestion newQuestion) => question.Add(newQuestion);

    /// <summary>
    /// Retries one of the choices for the question. Eg. choice A, choice B, choice C...
    /// </summary>
    /// <param name="choice">The index of the choice, eg. choice 2</param>
    /// <param name="index">The index of the question</param>
    /// <returns></returns>
    public string GetChoice(int choice, int index) => question[index].GetChoices(choice);

    /// <summary>
    /// Retrieves the index of the answer to the question
    /// </summary>
    /// <param name="questionIndex">The index of the answer</param>
    /// <returns></returns>
    public int GetAnswerIndex(int questionIndex) => question[questionIndex].Answer;

    /// <summary>
    /// Gets how many questions there are in the test
    /// </summary>
    /// <returns>The amount of questions in the test</returns>
    public int GetSize()
    {
        return question.Count;
    }
}

Студент Контроллера

    public class StudentController
{
    private List<Student> students;
    private FileManager fileManager;
    private Test test;

    public StudentController()
    {
        students = new List<Student>();
        fileManager = new FileManager();
        test = new Test();
        Init();
    }

    private void Init()
    {
        students = fileManager.LoadStudents();
        test = fileManager.LoadTest();
    }

    /// <summary>
    /// Verifies that the login details match what is in the system
    /// </summary>
    /// <param name="username">The username of the student</param>
    /// <param name="password">The password of the student</param>
    /// <returns>True if the credentials match that on the system</returns>
    public bool CheckLogin(int username, string password)
    {
        bool credentialsMatch = false;
        foreach (Student student in students)
        {
            if (student.ID == username && student.Password == password)
            {
                credentialsMatch = true;
                break;
            }
        }
        return credentialsMatch;
    }

    /// <summary>
    /// Fetches the index of the student in a list
    /// </summary>
    /// <param name="ID">The ID of the student</param>
    /// <returns>The student's ID if found, else returns -1</returns>
    public int GetStudentIndex(int ID)
    {
        int id = -1;
        foreach (Student student in students)
        {
            if (student.ID == ID)
            {
                id = ID;
                break;
            }
        }
        return id;
    }

    /// <summary>
    /// Sets the final mark of the student
    /// </summary>
    /// <param name="studentIndex">The index of the student</param>
    /// <param name="mark">The final mark of the student</param>
    public void SetFinalMark(int studentIndex, int mark) => students[studentIndex].SetFinalMark(mark);

    /// <summary>
    /// Sets the answer of the student at the current index
    /// </summary>
    /// <param name="studentIndex">The index of the student</param>
    /// <param name="questionNumber">The question number</param>
    /// <param name="answer">The answer for the student</param>
    public void SetStudentAnswer(int studentIndex, int questionNumber, int answer) => students[studentIndex].SetAnswer(questionNumber, answer);

    /// <summary>
    /// Adds a new answer to the list of the student's answers
    /// </summary>
    /// <param name="studentIndex">The index of the student</param>
    /// <param name="answer">The answer to add</param>
    public void AddStudentAnswer(int studentIndex, int answer) => students[answer].AddAnswer(answer);

    /// <summary>
    /// Gets the text for the question
    /// </summary>
    /// <param name="questionNumber">The question number</param>
    /// <returns>A string of the question's text</returns>
    public string GetQuestionText(int questionNumber) => test.GetQuestionText(questionNumber);

    /// <summary>
    /// Fetches the choice of the question at the index
    /// </summary>
    /// <param name="choice">The index of the choice</param>
    /// <param name="questionNumber">The question number</param>
    /// <returns></returns>
    public string GetQuestionChoice(int choice, int questionNumber) => test.GetChoice(choice, questionNumber);


    /// <summary>
    /// Gets the answer to the question
    /// </summary>
    /// <param name="questionNumber">The question number</param>
    /// <returns>The answer to the question</returns>
    public int GetAnswer(int questionNumber)
    {
        return test.GetAnswerIndex(questionNumber);
    }

    /// <summary>
    /// Saves the students to file
    /// </summary>
    public void SaveStudents()
    {
        fileManager.SaveStudents(students);
    }
}

Класс FileManger просто загружает и сохраняет объекты в файл. Любая помощь или рекомендации будут оценены!



Комментарии
2 ответа

Студент


  • В finalMark может быть общественная собственность, то вам не нужны геттеры и сеттеры.

  • answers есть несколько вопросов. Ваша реализация ограничивает внешний код, чтобы использовать его как массив. Нет никакого способа, чтобы запросить, сколько ответов в списке. Если внешний код не просит ответа 0,1,2,3,... она будет в конечном итоге запустить в IndexOutOfRangeException. Нет никакого способа, чтобы предотвратить это.

Упростить класс:

public class Student : User
{
public int FinalMark { get; set; }
public List<int> Answers { get; private set; }

public Student()
{
Answers = new List<int>();
}
}

Это работает точно так же, как ваш класс, с дополнительным преимуществом, избегая IndexOutOfRangeException и позволяет внешним абонентам использовать Answers список однако они хотят (как список, а массив, в foreach, ...)

Я тоже не фанат, касающиеся ответы для студентов. Я изменил это:


  • Тест имеет студент или учащийся тест (Какой вы предпочитаете)

  • Тест имеет вопросы.

  • Каждый вопрос содержит ответ студента (как собственность) или тест содержит отображение между вопросами и ответами (как вам больше нравится).

Поскольку Question содержит правильный ответ, я утверждаю, что данный ответ должен быть сохранен там, так что вы можете очень легко проверить, если правильный ответ был дан.

Это будет лучший подход ООП.

Также:


  • Это немного режет слух, что вы используете индекс сослаться на ответ, и использовать этот индекс за пределами класса вопрос. Этот показатель является бессмысленным , не зная ответа, он принадлежит.

Редизайн ответы относятся к вопросам позволит решить эту проблему.


MultipleChoiceQuestion


  • question и Question может быть сконденсирована в одном общественном Question собственность.

  • Возможно, это соответствует вашим текущим потребностям, но я бы избегал жестко 4 как ваш размер массива. Вы использовали List<int> в Student класс специально, чтобы вы могли развиваться в список. Я бы то же здесь.

  • Аналогично answers в Student класс, вы должны удалить открытые свойства и вместо того, чтобы сделать Choices общественный List<string> собственность, чтобы избежать вещи, как ArgumentOutOfRangeException и позволяя ваши ответы будут использованы в foreach.

  • Может быть, ненужные для ваших текущих потребностей, но вы могли бы изменить код, чтобы разрешить для multuple правильные ответы.

  • Я бы переименовал Answer для CorrectAnswerдля того, чтобы отличить правильный ответ от даны ответы.

Упростить класс:

public class MultipleChoiceQuestion
{
Public string Question { get; set; }

public List<string> Choices { get; private set; }

public int CorrectAnswer { get; set; }

public MultipleChoiceQuestion()
{
Choices = new List<string>();
}
}


Тест


  • Же замечания, как и раньше, не всегда делают приватные поля и открытые свойства. Если внешний абонент имеет доступ к обоим установки и получения значения, и вы не делаете каких-либо дополнительных работ, когда значение извлекается/устанавливается; тогда общественная собственность достаточно.

  • List<MultipleChoiceQuestion> question следует назвать questions потому что он содержит больше, чем один вопрос.

  • Я бы добавил Student здесь как свойство.

Это кажется, что будет лучше с точки зрения объектной модели. А Test затем объект, который содержит:


  • Студент, который сдает экзамен.

  • Вопросы, которые задают на тесте.

  • Ответы, которые студент дал.

Если вы храните данный ответ в тесте, или в самом вопросе, это вопрос предпочтений. Я бы поставил его в вопрос, но я допускаю, что это может быть субъективное предпочтение.


StudentController

Ничего необычного здесь. Вам нужно обновить код, согласно ранее предложенных улучшений.

Одна вещь, хотя:

public int GetStudentIndex(int ID)
{
int id = -1;
foreach (Student student in students)
{
if (student.ID == ID)
{
id = ID;
break;
}
}
return id;
}

Есть массивные разница между индексом студента, и его ID.

Предположим, я удалил студентов с id 4 и 5. Вашего выбора студента выглядит так:

0,1,2,3,6

Студент с id 6 имеет индекс 4! Как она стоит, ваш текущий код будет возвращать то же значение, которое вы прошли в нее, что несколько бессмысленно.
Единственным спасением здесь является то, что -1 указывает, что студент не существует. Однако, если это ваша единственная цель, вы должны изменить способ быть public bool StudentExists(int ID) чтобы сделать свое намерение явным.

Это часть большого вопроса, где вы сделали ставку по индексам гораздо больше, чем это принято в настоящее время код. Однако, как я не знаю, как далеко вы получили в вашей программе, я не уверен, если вы уже должны делать это лучше (или если вам все равно придется учиться этому в более позднем класс).

Что вы должны сейчас осознать, что индекс и код это две разные вещи:


  • Индекс-это позиция в массиве. Студента индекс зависит от многих студентов находятся в массиве перед ним.

  • Идентификатор персональный идентификационный студента. Это значение не будет меняться в зависимости от того, где студент находится в списке студентов.


Некоторые дополнительные советы

Это наверное выходит за рамки текущего задания, но они вещи, которые я бы изменить если бы это был профессиональный проект:


  • Вместо сохранения finalMark значение, вы могли бы вычислить его на лету. Если вы настроите свои занятия правильно, вы можете, например, посчитать int finalMark = myTest.Questions.Count(q => q.GivenAnswer == q.CorrectAnswer);

  • Как упоминалось ранее, я изменил вопрос, чтобы разрешить для нескольких правильных ответов.

  • Для более продвинутых тестов, вы захотите использовать Weight атрибут. Е. Г. Вопрос 1 стоит 5 очков => Weight = 5. Это помогает вам создавать тесты, где ответы на некоторые вопросы являются более важными, чем другие.

2
ответ дан 12 марта 2018 в 04:03 Источник Поделиться

Запутанной для меня

Студент имеет ответы, но они, кажется, не быть связаны с тестом.

Ответы должны быть конкретными испытанию. Студент либо имеет несколько тестов или тестового пользователя. Вы можете пройти тест базового класса, сырого теста, а затем класс testUser, который наследует от теста.

MultipleChoiceQuestion должны иметь правильный ответ, так что он может быть забит.

Тест должен иметь метод, результат.

Использовать публичные свойства На получить набор методов.

Вам не нужно установить на список. Они могут получить то добавить, изменить и удалить.

Вы можете просто новый такой и держать его в конструктор

private List<int> answers = new List<int>();  

В C# индексатор. Использование Индексаторов (На C# Руководство По Программированию)

0
ответ дан 8 марта 2018 в 08:03 Источник Поделиться