【问题标题】:Making a class that will contain a subclass that can be different classes depending on the need制作一个包含子类的类,该子类可以根据需要是不同的类
【发布时间】:2018-03-26 14:52:43
【问题描述】:

我不确定如何去实现这个特殊的想法,我有一个类,我们称之为 EnhancedUserInput,它将有一些变量,所有输入类型都将具有一个特定的子类,具体取决于操作期间的需要,所以一些额外的变量和一个列表,例如它的子类将是 MultipleChoice,它将具有 MinSelection、MaxSelection 和一个名为 option 的类型列表以及它们自己的变量等,然后是另一个可能的子类,称为 ExplicitAgreement,它具有变量 inputLabel1、inputLabel2 和BinaryInput 类型的列表,该列表将具有自己的变量。

到目前为止,据我所知,最好的方法是拥有某种类型的泛型变量?我将展示一些代码来尝试帮助获得我需要的东西,但我只是想知道是否有一种我不知道的简单方法可以做到这一点?

public class EnhancedCustomerInput
{
    public string Title { get; set;}

    public bool ResponseOptional { get; set;}

    public string CancelLabel { get; set;}

    public string SubmitLabel { get; set}

    // this is where I am unsure of how to go about it
    public object inputType
    {
        MultipleChoice
        ExplicitAgreement
    }
}

public class MultipleChoice
{
    public List<MultipleChoiceOption> Options { get; set; }

    public int MinSelected { get; set; }

    public int MaxSelected { get; set; }

}

public class ExplicitAgreement
{
    public List<BinaryInputOption> Buttons { get; set; }

    public string InputLabel1 { get; set; }

    public string InputLabel2 { get; set; }
}

这个解决方案的最佳途径是什么?我能想到一些可能的方法,但它们有点虚,想知道是否有任何简单的方法?

【问题讨论】:

  • 听起来你想使用Generics。输入类型应该是一个属性:public T InputType {get; set;}
  • 输入类型可以有不同数量的变量这一事实是否会成为问题。例如,每当我尝试分配诸如 model.inputType.Options[0].add(Option) 与 model.inputType.Buttons[0].add(Button) 之类的东西时,IDE 是否会计算出不同的变量(只是想在我走这条路之前确定一下)
  • 像“model.inputType.Buttons[0].add(Button)”这样的构造有一定的味道......泛型的一个更“老派”的替代品是接口......但让我们退后一步: 你想做什么?
  • 我的意思是代码气味。这种结构的用户必须对数据结构了解太多。您最终会得到高度复杂、极难维护的代码。
  • 是的,我确实觉得它会有点像丛林,所以想知道是否有更简单的解决方案来解决我目前的想法:/ .

标签: c# class subclass


【解决方案1】:

在我看来,您可能有错误的方法。也许你想要的只是使用类继承?

public class EnhancedCustomerInput
{
    public string Title { get; set;}
    public bool ResponseOptional { get; set;}
    public string CancelLabel { get; set;}
    public string SubmitLabel { get; set}
}

public class MultipleChoice : EnhancedCustomerInput
{
    public List<MultipleChoiceOption> Options { get; set; }
    public int MinSelected { get; set; }
    public int MaxSelected { get; set; }
}

public class ExplicitAgreement : EnhancedCustomerInput
{
    public List<BinaryInputOption> Buttons { get; set; }
    public string InputLabel1 { get; set; }
    public string InputLabel2 { get; set; }
}

【讨论】:

  • 我正在考虑这样做,但这需要为我的每个子类制作不同的方法来传递和构建最终目标是使用它来收集用户的输入以构建 XML 字符串被送走,所以希望让基数保持不变,并根据需要的输入类型改变输入类型子类(抱歉解释不佳,我的头炸了atm)
  • 如果您可以在问题中添加对您的实际目标的简明解释,则可以提出更复杂的建议。我不明白为什么史蒂夫的方法会违背您在上述评论中描述的目标。 @C.Dodds
  • 模型在程序启动时被初始化为一个类型,但是直到用户选择他们想要的输入类型并且相应的输入字段将出现供他们选择,例如一堆文本框,用于显示与按钮一起显示的文本。因为我不知道用户在程序启动时会选择什么输入类型,所以我希望让它动态化,并在用户做出选择后允许它的结构发生变化(如果可能的话)我在考虑泛型
  • 那是 Winforms 还是 WPF 还是...? @C.Dodds
  • @C.Dodds:基于这些 cmets,听起来我在回答中提供的最后一个选项可能很合适。您可以将下拉菜单绑定到 enum 属性,并根据用户的输入切换作为子选项提供的对象类型。反序列化时,您可以访问一个值,该值定义您需要将 InputData 反序列化为哪种类型。
【解决方案2】:

史蒂夫哈里斯的继承建议很好。您使用 Composition 的原始选项也可以正常工作:

public class EnhancedCustomerInput
{
    public string Title { get; set;}

    public bool ResponseOptional { get; set;}

    public string CancelLabel { get; set;}

    public string SubmitLabel { get; set; }

    public object InputData { get; set; }
}

唯一的问题是您的代码的使用者需要知道InputData 可以是几种不同类型之一,并且您可能需要switch 对其类型的逻辑。你可以在属性中添加 cmets 给人们一个提示,或者你可以使用类似 LanguageExt 的库,它提供了一个Either 类型:

public class EnhancedCustomerInput
{
    public string Title { get; set;}

    public bool ResponseOptional { get; set;}

    public string CancelLabel { get; set;}

    public string SubmitLabel { get; set; }

    public Either<MultipleChoice, ExplicitAgreement> InputData { get; set; }
}

这使得InputData 可以是哪些类型更加明显,但如果您有两种以上的可能性,则会变得非常笨拙。

您还可以声明InputData 必须实现的接口,这将使开发人员更容易找到打算在其中使用的所有类型。但是空接口被认为是代码异味,因为它表明您正在将接口用于它们并非真正想要的用途。

我发现另一个效果很好的选项是定义一个enum 类型来帮助识别您可以拥有哪些不同类型的输入数据:

public class EnhancedCustomerInput
{
    public string Title { get; set;}

    public bool ResponseOptional { get; set;}

    public string CancelLabel { get; set;}

    public string SubmitLabel { get; set; }

    public InputType InputType { get; set; }

    public object InputData { get; set; }
}

public enum InputType { MultipleChoice, ExplicitAgreement }

这为您的业务逻辑提供了一组特定的可能类型,您可以在 switch 您的逻辑上使用这些类型,并且在要对类进行序列化和反序列化时工作得特别好,因为这样您就可以告诉反序列化器哪个特定类型要反序列化 InputData 的对象。

有很多选择,每个都有自己的优点和缺点。

【讨论】:

    猜你喜欢
    • 2014-05-25
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    相关资源
    最近更新 更多