【问题标题】:C# enum that depends upon another enum [or maybe this is more design related]依赖于另一个枚举的 C# 枚举 [或者这可能与设计更相关]
【发布时间】:2009-11-04 22:50:46
【问题描述】:

我可能走错了方向,所以让我试着整理一下我的想法(希望能从你们那里得到一些提示):

想象一个枚举:

public enum ReportType
{
   Performance,
   Trending,
   Statistical
}

此枚举也将是表单构造函数的属性或参数。 ReportType 的值将决定以下内容:

a) the text displayed at the top of the form
b) Which controls are visible
c) the text for a combobox <---!!!! this is where the 2nd enum comes in

关于第二个枚举,如果它是 Performance ReportType,我想要:

public enum PerformanceGraph
{
    Bar,
    Line,
    Pie,
    Area
}

如果它是趋势,我会想要:

public enum TrendingGraph
{
    Bar,
    Line
}

这个表单只是收集用户输入。我的意思是,我宁愿不为一个简单的表单进入一些复杂的继承结构。当我可以快速执行以下操作时,似乎需要付出很多努力(我可能是错的):

(想象一下这个构造函数)

public ReportInputForm(ReportType RptType)
{
    m_RptType = RptType;

    if (RptType == ReportType.Performance)
    {
        this.Text = "Performance Title";
        this.CheckBoxCtl.Visible = false;
        this.GraphCombo.Items.AddRange(Enum.GetNames(typeof(PerformanceGraph)));
        this.GraphCombo.SelectedIndex = (int)PerformanceGraph.Bar;
    }
    else if (RptType == ReportType.Trending)
    {
         // blah, blah
    }
    else if (RptType == ReportType.Statistical)
    {
        // blah, blah
    }
    else
    {
        throw new ArgumentException("Invalid ReportType enum value");
    }
}

当您想用 GraphCombo 实际做某事时,它开始变得棘手,因为现在您需要知道它是哪个 ReportType 用于强制转换。

另外,回到我的构造函数,假设我想向它发送一个图形值,以便我们可以设置 GraphCombo 的 SelectedIndex(这可能是用户最后选择的值,而不是设置某种默认值)。嗯....

 public ReportInputForm(ReportType RptType, ???WhichGraphEnum???)
 {
 }

我的意思是,现在有三个图形枚举,因为有三个 ReportType。另外,想象一下再添加几个 ReportType。

我想我可以使用 int/long:

 public ReportInputForm(ReportType RptType, int lastGraphType)
 {
 }

但我想我想在这里通过编译时检查成为 Enum 先生。换句话说,如果我可以使用某种类型的枚举(像这样),我可以检测到错误:

ReportInputForm foo = new ReportInputForm(ReportType.Trending, GraphType.Area);

相对于:

// Is 4 even a valid graph type for the trending report?  Answer: No
ReportInputForm foo = new ReportInputForm(ReportType.Trending, 4);

我已经说得够多了。也许这更像是一个设计问题,而不是与枚举相关的问题。我只是在寻找一些关于如何解决这个问题的想法。谢谢!

################################################# ################################ ################################################# ################################ ####################### 编辑从这里开始###################### ################# ################################################# ################################ ################################################# ################################

这是对使用泛型的回应(如果我有点慢,我深表歉意;谢谢 Daniel 的回复):

这是一个建议:

ReportInputForm<TrendingReport> = new ReportInputForm<TrendingReport>(GraphType.Area);

好的,所以如果我要使用泛型(和表单),我必须创建一个类型。我在想象这样的事情(我们现在只公开一个函数,设置标题):

public abstract class ReportType
{
    public abstract string GetTitle();
}

public class PerformanceReport : ReportType
{
    public PerformanceReport()
    {
    }

    public override string GetTitle()
    {
        return "This is my Performance title";
    }
}

public class TrendingReport : ReportType
{
    public TrendingReport()
    {
    }

    public override string GetTitle()
    {
        return "This is my Trending title";
    }
}

public partial class Form1<T> : Form
    where T : ReportType, new()
{
    T foo = null;
    public Form1()
    {
        InitializeComponent();
        foo = new T();
        this.Text = foo.GetTitle();
    }
}

所以,现在我可以执行建议的操作了:

Form1<TrendingReport> f = new Form1<TrendingReport>();

这很酷,而且有效(我的标题取决于类型),但我认为这对我最初的问题没有帮助。第二个枚举。

如果我使用的是 PerformanceReport,我希望我的 GraphType 枚举为:

public enum PerformanceGraph
{
    Bar,
    Line,
    Pie,
    Area
}

如果我使用 TrendingReport,我希望我的 GraphType 枚举为:

public enum TrendingGraph
{
    Bar,
    Line
}

换句话说,这个枚举依赖于类(或者如我最初的问题所述,依赖于第一个枚举)。

我的意思是,我想我可以在抽象类中放置一个包含所有图形类型的枚举:

public abstract class ReportType
{
    public enum GraphType
    {
        Bar,
        Line,
        Pie,
        Area
    }

    public abstract string GetTitle();
}

但是,这违背了我最初问题的目的。因为这现在变得合法了(想象一下我修改了 Form1 的构造函数):

Form1<TrendingReport> f = new Form1<TrendingReport>(ReportType.GraphType.Pie);

请记住,TrendingReport 应该只有 Bar 和 Line。我正在尝试编译时检查这一点。我肯定也遗漏了一些东西(关于泛型)。

【问题讨论】:

  • 对我来说,我觉得这更像是一个设计问题,不是很糟糕,只是需要一些调整以实现可重用性和减少代码混乱。
  • 您实际上并不需要“精心设计的继承层次结构”。单个抽象 Report 基类和允许类型的每个子类枚举将为您提供所需的一切,而无需所有复杂的 ifs/switching。

标签: c# enums


【解决方案1】:

如果表单的 type 取决于枚举的值,我会将枚举本身转换为类型。然后将表单类设为通用。

例如:

ReportInputForm<TrendingReport> = new ReportInputForm<TrendingReport>(GraphType.Area);

甚至:

ReportInputForm<AreaGraph> = new TrendingReportForm<AreaGraph>();

假设TrendingReportFormReportInputForm 的子类。

任何时候,如果您的类的行为会根据某个枚举值发生变化,您应该寻找机会将不断变化的行为重构为可以委托给子类的单独方法。

【讨论】:

  • 我认为将通用功能移动到表单使用的单独类会更好。让表单本身具有通用性会使 IDE 和设计人员的事情变得棘手。
  • @Snarfblam:不过,大概你要用视觉设计器编辑的唯一表单是基类。我可能会反转它,并创建一个由表单类参数化的通用类(不是Form 的子类),例如TrendingReport&lt;ReportInputForm&gt;——根据应用程序,这甚至可能是最好的解决方案。
  • 我可能有点慢......但我认为我不明白如何使用泛型来解决我原来的问题。我将编辑我的原始问题,以便我可以提供代码。
【解决方案2】:

这听起来像是一个使用继承的完全合理的地方,有一个基类ReportInputForm 和子类PerformanceReportInputFormTrendingReportInputFormStatisticalReportInputForm。它似乎不是特别复杂,它巧妙地避免了任何 switch/case 语句或长 if 链,同时保持编译时类型检查。或者,您可以根据策略模式来实现它,这会增加一些脚手架和开销,但允许您动态更改报告类型。

【讨论】:

  • 我选择了接近这个的东西。一个抽象基类(ReportType),有四个继承自它的类(基本上这些类有一堆getter)。我在表单之外构造我想要的继承类型,然后将其传递给表单,并在我需要特定于该类型的某些内容时使用该 ReportType(消除一些 if/else 语句)。
【解决方案3】:

通用形式?

  ReportInputForm<T>

【讨论】:

    猜你喜欢
    • 2014-10-09
    • 1970-01-01
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    相关资源
    最近更新 更多