如何避免在C#中进行类型检查以加载正确的UI?

时间:2019-11-30 13:43:01

标签: c# winforms generic-programming open-closed-principle

我正在使用WinForms构建具有2种模式的简单测验程序:

1)编辑模式:用户可以在其中创建自己的问题

2)测验模式:用户需要回答问题的地方

当前有两种类型的问题:开放(问题和自由文本框)和多项选择(问题和4个可能的答案)。

我为一个问题创建了一个抽象类:

insert into animal_in_zoo (zooid, animalid)
    select z.id, a.id
    from zoos z cross join
         animals a;

还有2个继承该类的子类:

public abstract class Question
{
    public string QuestionString { get; private set; }
    public Question(string q)
    {
        QuestionString = q;
    }
}

我将所有创建的问题保存在public class OpenQuestion : Question { public string CorrectAnswer { get; private set; } public OpenQuestion(string q, string a) : base(q) { CorrectAnswer = a; } } public class MultipleChoiceQuestion : Question { public string[] Answers { get; private set; } public MultipleChoiceQuestion(string q, string[] ans) : base(q) { Answers = ans; } } 中,最终保存为JSON文本文件。

我的问题是加载问题,如何加载正确的UI?

对于未解决的问题,将有一个带有问题和文本字段的标签来写出答案, 对于选择题,将有问题标签和4个单选按钮。

目前这是我要做的:

List<Question>

是否有避免这种类型检查的方法?因为在我看来这是不对的,所以如果我要添加另一种类型的问题,则需要回到该方法并为该类型添加另一种条件。

编辑对于UI,我使用保存UI的面板,例如:

public void LoadNextQuestion()
{
    Question q = GetCurrentQuestion(); // Just returning the current question to show
    if(q is OpenQuestion) // And here is the problematic part.
    {
        ShowOpenQuestion(q as OpenQuestion); // Load UI for open question
    }
    else if(q is MultipleChoiceQuestion)
    {
        ShowMultipleChoiceQuestion(q as MultipleChoiceQuestion); // Load UI for Multiple choice question
    }
}

预先感谢

2 个答案:

答案 0 :(得分:1)

类型检查是您的朋友。请勿进行类型检查。甚至还有向add/use more of it的转移。充其量您可以得到别人的代码为您做类型检查(例如Function调用解析)。

但是,在您给出的示例中,我看不到很多问题。如果有的话,如果您继续自己这样做,将是有益的,因为这样可以避免出现问题。我什至都不会想到六种“问题类型”-因此,从任何角度看,这份清单都不是很长。

您可以做的第一件事是用开关/保护套代替那些if / eles。他们最近被赋予了模式匹配能力。实际上,基于类型的转换和处理是first thing added之一。该示例代码就在您现在所做的事情附近。如果使用switch,则应使用默认值来显示一些错误消息,甚至引发异常。这样可以避免将来发生问题(忘记为新类提供适当的代码。其他人通过不提供绘画功能来弄乱继承)。

当然,通常可以使用集合来替换开关/外壳。 Dictionary<type, DelegateThatTakesAnyQuestionInstance>。您必须在Delegate中进行手动转换(除非这里有共同或冲突帮助?),但是您知道它匹配。使用Lambdas而不是Delegate的命名函数,您甚至可以将整个代码隐藏在定义的其他大型集合中。同样,没有匹配项可以通知您,但例外情况除外。

在我撰写本文时,您没有指定编程环境。但是值得指出的是,如果您使用WPF / UWP并遵循MVVM,则可以为您提供一个很好的帮助:我称它们为“ Type Targeting Data Tempaltes”。如果您在View上抛出一些随机类,但没有更高阶的东西适用,它将尝试找到匹配的Template来显示它。使用TargetType property

答案 1 :(得分:0)

总的来说,答案是通过以下方法应用信息隐藏和封装的面向对象设计原则:

  • 让您的抽象Question类指定一种抽象方法,该方法为特定类型的问题呈现UI,并且
  • 在每个具体子类(即OpenQuestionMultipleChoiceQuestion中覆盖该方法。

更具体地讲,有关这些方法应如何呈现UI的“确切”答案取决于您所使用的UI范例和框架。

  • 关于UI范式,您需要确定是否使用MVVM(模型,视图,ViewModel),MVC(模型,视图,控制器)或其他方法。
  • 假设这是关于桌面应用程序的,那么在框架级别,您可以在Windows Forms和WPF之间进行选择,这两者都提供了不同的方式来以某种或多或少的方式进行此操作。对于MVVM,我的选择是WPF。
  • 除了在Windows窗体和WPF之间的基本选择之外,还有多个UI框架或库(例如MVVMlight,仅举一例),它们提供了强大的功能来应对UI编程的典型挑战(例如事件,命令) )。