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

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

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

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

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

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

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

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

以及继承该类的2个子类:

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;
    }
}

我将所有创建的问题保存在 List<Question> 中, 并最终以 JSON 形式出现在文本文件中。

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

对于开放式问题,会有一个带有问题和文本字段的标签来写答案, 对于多项选择题,会有问题标签和 4 个单选按钮。

目前我是这样做的:

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
    }
}

有没有办法避免这种类型检查?因为它对我来说看起来不对,所以如果我要添加另一种类型的问题,我需要返回到此方法并为该类型添加另一个条件。

编辑 对于 UI,我使用包含 UI 的面板,例如:

public void ShowOpenQuestion(OpenQuestion oq)
{
    openQuestionPanel.Visible = true;
    multipleChoicePanel.Visible = false; // Hide other question type panels, currently there is only one more
    openQuestionLabel.Text = oq.QuestionString;
    openQuestionInputField.Text = string.Empty;
}

提前致谢

最佳答案

类型检查是你的 friend 。不要对抗类型检查。甚至还有移动到add/use more of it .充其量你可以让其他人的代码为你做类型检查(比如函数调用解析)。

但是,在您给出的示例中,我没有看到很多问题。如果有的话,如果您继续自己做,那将是有益的,因为它可以避免日后出现问题。我什至想不出六种“问题类型”——所以不管怎么衡量,这个列表都不会很长。

您可以做的第一件事是用 switch/case 替换那些 if/elses。他们最近获得了模式匹配能力。事实上,基于类型的类型转换和加工是 first thing added 之一。 .示例代码恰好与您现在所做的有关。如果你使用 switch,应该使用 default 来显示一些错误信息甚至抛出异常。这就是您避免 future 问题的方式(忘记为新类提供正确的代码。其他人通过不提供绘制功能来搞乱继承)。

当然,switch/Case 通常可以用 Collection 代替。 Dictionary<type, DelegateThatTakesAnyQuestionInstance> .您必须在 Delegate 中进行手动转换(除非这里有共同或矛盾帮助?),但您知道它匹配。使用 Lambdas 而不是委托(delegate)的命名函数,您甚至可以将整个代码与您定义的其他大型集合一起隐藏在某个地方。同样,除非有异常(exception),否则任何匹配项都不应该给您通知。

我写这篇文章时你没有指定你的编程环境。但值得指出的是,如果您使用 WPF/UWP 并且遵循 MVVM,那么有一个很好的 helper 适合您:我称它们为“Type Targetting Data Tempaltes”。如果你在 View 中抛出一些随机类并且没有更高阶的东西适用,它会尝试找到一个匹配的模板来显示它。使用 TargetType property .

关于c# - 如何避免在 C# 中进行类型检查以加载正确的 UI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59116736/

相关文章:

javascript - 通过 WinForm 查看 Google 日历

c# - 从 ASPX/C# 页面发送 APNS,使用 SSL 进行身份验证

c# - 取消缩放 map 控制 Windows Phone

c# - 将 SQL 语句转换为 Linq-2-Sql

java - 我如何进行泛型泛型?

c# - 解决依赖关系和构建树的算法

c# - 具有通用返回类型但不是通用输入的方法。这可能吗?

c# - NuGet 包(.NET Standard 2.x)打破 ASP.NET MVC5 应用程序(.NET 完整框架)

c# - 如何在C#中隐藏或取消隐藏表单

.net - 如何在VB.NET中画一条线