The reason that some questions are asked multiple times is due to the way the code handles the case where a randomly selected question has been asked before.
Consider on the first time through (when no questions have been asked before), let's say Question 5 is randomly selected. The if statement will be false and will mark Question 5 as 'has been asked' and will return the number 5. So far so good.
However, some time later, Random.Next might return 5 again. This time the if statement is true and you recursively seek another number (if you're lucky). Let's say that this call to GetRandomNumber returns, let's say, the value 8. However this value is discarded and the original function call proceeds to return the value 5 (which is an already asked question number).
You might want to consider what happens when you run out of questions?
Perhaps a better approach is to build a list of question numbers, and then as they are used, remove them from the list, until the list is empty.
using System;
using System.Collections.Generic;
namespace TwentyQuestions
{
public class Quiz
{
private const int NUM_QUESTIONS = 20;
private List<int> UnaskedQuestions = new List<int>();
private Random _rnd = new Random();
public Quiz()
{
for (int i = 0; i < NUM_QUESTIONS; i++)
UnaskedQuestions.Add(i+1);
}
public void Run()
{
try
{
while (true)
AskQuestion(GetRandomNumber());
}
catch (ApplicationException Ex)
{
Console.WriteLine(Ex.Message);
}
}
public int GetRandomNumber()
{
if (UnaskedQuestions.Count == 0)
throw new ApplicationException("No more questions");
int returnpoint = _rnd.Next(UnaskedQuestions.Count);
int questionNumber = UnaskedQuestions[returnpoint];
UnaskedQuestions.RemoveAt(returnpoint);
return questionNumber;
}
public void AskQuestion(int QuestionID)
{
Console.Write("Answer question " + QuestionID.ToString() +
" (or blank to exit)? ");
string answer = Console.ReadLine();
if (String.IsNullOrEmpty(answer))
throw new ApplicationException("Blank answer");
}
}
}