匿名函数列表或成千上万的类列表

3

我希望创建一个在线测验,可以从数千个编程问题中随机抽取任何问题进行提问。每个问题都是通过一个函数创建的,该函数接收一个整数数组作为参数,其值确定显示的确切问题。我已将每个问题作为一个类:

public class AddingTwoDigitNumbers : IQuestion
{
    public string QName() { return "Adding Two-Digit Numbers" };
    public int[] QParams() { return int[]() {Random(10, 99), Random(10, 99) };
    public void Question(int[] values) {
        Console.WriteLine(string.Format("What is {1} + {2}?", values[0], values[1]);
    }
    public void Answer(int[] values) {
        Console.WriteLine(values[0] + values[1]).ToString());
    }
}

QParams创建一个int数组(用于确定所创建的问题),然后将其传递给QuestionAnswer来创建问题和答案。

我希望能够通过QName搜索到问题列表,但不想创建(和命名)成千上万个实现IQuestion的类。

因此,这是我的第二个解决方案:

public class Question
{
    public string QName { get; set; }
    public Func<int[]> QParams { get; set; }
    public Action<int[]> Question { get; set; }
    public Action<int[]> Answer { get; set; }
}

public class QuestionRepository
{
    public static Dictionary<string, Question> Questions = new Dictionary<string, Question>();
    public static void AddQuestions(Question[] qs) {
        foreach (Question q in qs) Questions.Add(q.QName, q);
    }
}

public class FirstSetOfQuestions
{
    static void AddQuestions()
    {
        QuestionRepository.AddQuestions(new Question[]
        {
            new Question()
            {
                QName = "Adding Two-Digit Numbers",
                QParams = () => int[]() {Random(10, 99), Random(10, 99) },
                Question = (v) => {Console.WriteLine(string.Format("What is {1} + {2}?", v[0], v[1]);},
                Answer = (v) => {Console.WriteLine(values[0] + values[1]).ToString());}
            },
            new Question()
            {
                QName = "Subtracting Three-Digit Numbers",
                QParams = () => int[]() {Random(100, 999), Random(100, 999) },
                Question = (v) => {Console.WriteLine(string.Format("What is {1} - {2}?", v[0], v[1]);},
                Answer = (v) => {Console.WriteLine(values[0] - values[1]).ToString());}
            }
        }
    }
}

我的问题是哪种方法更好?我应该创建数千个类,为每个类提供名称,还是创建数千个匿名函数并使用(我假设)委托将它们存储在一个类中?如果我有成千上万个问题,第二种解决方案是否存在问题,或者有更好的方法来解决这个问题?(显然,我想要创建的问题比这里展示的复杂得多,涉及分数,代数等)。

4
为什么不将问题数据存储在数据库中? - Alex
3
你可以存储一个表达式,甚至可以存储C#代码并即时编译它。 - SimpleVar
1
我不熟悉任何好的表达式序列化库,但存储代码非常简单。你只需存储代码的文本(例如 "x + y = Math.PI")。稍后编译它时,可以使用 CSharpCodeProvider,根据需要添加所需的命名空间和变量声明。 - SimpleVar
1
@CapIsland:如果是这样,我认为更好的方法是通过某个应用程序领域将IQuestion实现捆绑在一起成为程序集(例如,“三角函数问题”)。在运行时作为插件加载它们,并在需要添加另一个问题时保持测验“核心”不变。使用带有C#代码和某种管理工具的数据库是无法帮助您的,因为那样您将需要良好的代码和/或表达式编辑器(而现在您已经拥有它 - Visual Studio)。 - Dennis
1
@CapIsland "Skeet"? 那可是Skeet先生对你! - user146043
显示剩余21条评论
2个回答

3

为了让您开始使用流畅的语法,我们在其中加入了一些存根和想法。

class Question
{
    public string Name { get; set; }
    public string QuestionFormat { get; set; }
    public List<Range> Args { get; set; }
    public Expression<Func<int[], int>>  ValExp { get; set; }

    public Question(string name, string questionFormat)
    {
        this.Name = name;
        this.QuestionFormat = questionFormat;
        this.Args = new List<Range>();
    }

    public Question Rand(int min, int max)
    {
        this.Args.Add(new Range(min, max));
        return this;
    }

    public void Val(Expression<Func<int[], int>> exp)
    {
        this.ValExp = exp;
    }

    public CompiledQuestion Compile()
    {
        // Generate args in the appropriate ranges
        // Evaluate the result with the ValExp
        // Return a new CompiledQuestion with the information -
        //    basically just replacing Args, ValExp with RealArgs, Val
    }

    public ICoolDataObject Save()
    {
    }

    public static Question Load(ICoolDataObject hmm)
    {
    }
}

class Range
{
    public int Min { get; set; }
    public int Max { get; set; }

    public Range(int min, int max)
    {
        this.Min = min;
        this.Max = max;
    }
}

现在创造问题几乎是一件有趣的事情:

new Question("simple addition",
             "whats {0} + {1}?")
    .Rand(10, 99)
    .Rand(10, 99)
    .Val(v => v[0] + v[1]);

在工作时间很晚的情况下,您可以明显地添加一些验证检查来避免错误的参数数量,并且在需要时使用doubledecimal,而不是int


非常感谢您。这真的很酷,可能会证明有用。 - CapIsland

2
两种方法都是错误的。我假定你不会有成千上万种不同的计算方式,你只会有大约十几个或几十个不同的计算方式,作用于各种各样的数据。
所以,你需要对数据进行规范化,以便在一组定义良好的数据的数据库上得到大约十几个或几十个不同的明确定义的计算,并且为每种类型的计算编写大约十几个或几十个类,仅此而已
你可能认为这太复杂了,你可能认为写成千上万个类(或委托,实际上并不重要)可能是很多工作量,但每个部分都是小而简单的,相信我,一旦界面或所有这些类的实现需要更改,你将非常后悔采用这种方式,并且最有可能在某个时刻需要进行更改。

我在类中有很多计算。我已经为点、直线、分数、方程等创建了类。这大大减少了“问题”和“答案”函数的复杂性。 - CapIsland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接