簡體   English   中英

如何避免在 C# 中進行類型檢查以加載正確的 UI?

[英]How to avoid type checking in C# to load correct UI?

我正在使用具有兩種模式的 WinForms 構建一個簡單的測驗程序:

1) 編輯模式:用戶可以在這里創建自己的問題

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

提前致謝

類型檢查是你的朋友。 不要與類型檢查作斗爭。 甚至有一種運動來添加/使用更多它 充其量你可以讓別人的代碼為你做類型檢查(比如函數調用解析)。

但是,在您給出的示例中,我沒有看到很多問題。 如果有的話,如果你自己繼續做這件事會很有好處,因為它會避免問題。 我什至想不出半打“問題類型”——所以這個列表不會像任何衡量標准一樣長。

您可以做的第一件事是用 switch/case 替換那些 if/else。 他們最近獲得了模式匹配能力。 事實上,基於類型的鑄造和處理是添加第一件事 示例代碼正好與您現在所做的有關。 如果使用 switch,則應該使用默認值來顯示一些錯誤消息甚至拋出異常。 這就是您避免未來問題的方法(忘記為新類提供正確的代碼。其他人通過不提供繪制功能而弄亂了繼承)。

當然,通常可以用 Collection 替換 switch/Case。 Dictionary<type, DelegateThatTakesAnyQuestionInstance> 您必須在 Delegate 中進行手動轉換(除非這里的協方差或逆方差幫助?),但您知道它匹配。 並且使用 Lambda 代替 Delegate 的命名函數,您甚至可以將整個代碼與您定義的其他大型集合一起隱藏。 同樣,沒有匹配項應該給你一個通知,除非是例外。

我寫這個的時候你沒有指定你的編程環境。 但值得指出的是,如果您使用 WPF/UWP 並遵循 MVVM,那么有一個很好的幫手:我稱它們為“類型目標數據模板”。 如果你在 View 中拋出一些隨機類並且沒有更高階的東西適用,它會嘗試找到一個匹配的模板來顯示它。 使用TargetType 屬性

您可以稍微更新基礎Question類並添加ShowQuestion方法,該方法將由繼承者實現

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

    public abstract void ShowQuestion();
}

但是此解決方案不允許您拆分問題的邏輯及其UI表示形式,您可能會考慮使用MVVM或MVP模式將UI和邏輯分開

一般而言,答案是通過以下方式應用信息隱藏和封裝的面向對象設計原則:

  • 讓您的抽象Question類指定一個抽象方法,該方法為特定類型的問題呈現 UI 和
  • 在每個具體子類中覆蓋該方法,即OpenQuestionMultipleChoiceQuestion

在更具體的層面上,關於這些方法應該如何呈現 UI 的“確切”答案取決於您使用的 UI 范例和框架。

  • 關於UI范式,你需要決定是否使用MVVM(模型、視圖、視圖模型)、MVC(模型、視圖、控制器)或其他方法。
  • 假設這是一個桌面應用程序,在框架級別,您可以在 Windows 窗體和 WPF 之間進行選擇,這兩者都提供了不同的方法來以或多或少的優雅方式完成此操作。 對於 MVVM,我的選擇是 WPF。
  • 除了 Windows 窗體和 WPF 之間的基本選擇之外,還有幾個 UI 框架或庫(例如,MVVMlight,僅舉一例)提供強大的功能來解決 UI 編程的典型挑戰(例如,事件、命令)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM