表单和用户控件的基础 class
One base class for both forms and user controls
我有一个 Form
有几种输入验证方法。我希望在多个 Form
和 UserControl
之间共享此验证逻辑。 base class 的类型应该是什么?它不能是 Form
,因为它也将用于 UserControl
,它不能是 UserControl
,因为它也将用于 Form
。
我的直觉告诉我,解决方案可能涉及泛型,但我不确定。
注: By "validation logic" 我指的是实现,所以接口不是解决方案。
编辑(使问题更清楚一点):我确实有一个单独的class用于实际验证输入。但是,我使用 ErrorProvider
来指示用户输入无效。我的 InputValidator
class 使用 ErrorProvider
调用 Form
/UserControl
中的一个方法向用户显示错误。我只是不想为每个 Form
/UserControl
.
复制粘贴此方法
您不能创建同时处理 Forms 和 UserControls 的基础 class。但是,您可以为您的表单创建一个基础 class,为您的用户控件创建另一个基础。
此外,创建一个接口,基 classes 实现并发布您需要在验证器中使用的成员。
通过这种方法,重复的代码量至少减少到两个位置。请注意,有些 OOP 实践在 Windows 表单(例如抽象 classes)的上下文中不起作用,因为设计者引入了一些限制。
原回答:
在这种情况下,最好的选择是将验证逻辑移动到它自己的单独 class 中。您可以在窗体和用户控件中使用这个新的 class。
如果在验证时需要引用Form或UserControl,可以使用ContainerControl类型的参数。此 class 是 Form 和 UserControl 的基础 class。这样,您可以创建适用于所有继承自 ContainerControl 的 class 的共享逻辑。
使用组合而不是继承。参见:Composition over inheritance(维基百科)。
您的表单必须继承自 Form
或继承自 Form
的另一个表单。您的用户控件必须继承自 UserControl
或继承自 UserControl
的另一个用户控件。您无法更改此设置,因此您无法为它们提供自己的基础 class。
相反,在单独的 class 中实现您的验证逻辑,并在您的表单和用户控件中使用它。
public partial class MyForm : Form
{
private readonly MyValidation _validation;
public Myform()
{
InitializeComponent();
_validation = new MyValidation(errorProvider1);
}
//TODO: use _validation instead of inherited validation logic.
}
由于我不知道您的验证是什么,因此我无法为您提供有关如何准确实施此功能的更多详细信息。
第一件事是第一 - 我认为 Olivier 的回答非常好,我建议你使用它。
但是,虽然您不能更改 Form
和 UserControl
的基础 classes,但仍然有一种方法可以使用接口和扩展方法仅编写一次方法 - 这这就是我想在此处的回答中显示的内容。
接口:
internal interface IValidatable
{
ErrorProvider ErrorProvider {get;}
}
分机 class:
internal static class IValidatableExtensions
{
internal void ShowValidationResult(this IValidatable self, ValidationResult result)
{
// Here you can use self.ErrorProvider to show your results
}
}
现在您可以让您的表单和用户控件实现 IVilidatable
接口,并且在验证 class 中只需调用 ShowValidationResult
方法。
同样,我会简单地向验证实例发送对 errorProvider 的引用,正如 Olivier 在他的回答中所展示的那样,但这种技术在其他情况下可能会有用,所以我想我最好自己添加一个答案。
我有一个 Form
有几种输入验证方法。我希望在多个 Form
和 UserControl
之间共享此验证逻辑。 base class 的类型应该是什么?它不能是 Form
,因为它也将用于 UserControl
,它不能是 UserControl
,因为它也将用于 Form
。
我的直觉告诉我,解决方案可能涉及泛型,但我不确定。
注: By "validation logic" 我指的是实现,所以接口不是解决方案。
编辑(使问题更清楚一点):我确实有一个单独的class用于实际验证输入。但是,我使用 ErrorProvider
来指示用户输入无效。我的 InputValidator
class 使用 ErrorProvider
调用 Form
/UserControl
中的一个方法向用户显示错误。我只是不想为每个 Form
/UserControl
.
您不能创建同时处理 Forms 和 UserControls 的基础 class。但是,您可以为您的表单创建一个基础 class,为您的用户控件创建另一个基础。
此外,创建一个接口,基 classes 实现并发布您需要在验证器中使用的成员。
通过这种方法,重复的代码量至少减少到两个位置。请注意,有些 OOP 实践在 Windows 表单(例如抽象 classes)的上下文中不起作用,因为设计者引入了一些限制。
原回答:
在这种情况下,最好的选择是将验证逻辑移动到它自己的单独 class 中。您可以在窗体和用户控件中使用这个新的 class。
如果在验证时需要引用Form或UserControl,可以使用ContainerControl类型的参数。此 class 是 Form 和 UserControl 的基础 class。这样,您可以创建适用于所有继承自 ContainerControl 的 class 的共享逻辑。
使用组合而不是继承。参见:Composition over inheritance(维基百科)。
您的表单必须继承自 Form
或继承自 Form
的另一个表单。您的用户控件必须继承自 UserControl
或继承自 UserControl
的另一个用户控件。您无法更改此设置,因此您无法为它们提供自己的基础 class。
相反,在单独的 class 中实现您的验证逻辑,并在您的表单和用户控件中使用它。
public partial class MyForm : Form
{
private readonly MyValidation _validation;
public Myform()
{
InitializeComponent();
_validation = new MyValidation(errorProvider1);
}
//TODO: use _validation instead of inherited validation logic.
}
由于我不知道您的验证是什么,因此我无法为您提供有关如何准确实施此功能的更多详细信息。
第一件事是第一 - 我认为 Olivier 的回答非常好,我建议你使用它。
但是,虽然您不能更改 Form
和 UserControl
的基础 classes,但仍然有一种方法可以使用接口和扩展方法仅编写一次方法 - 这这就是我想在此处的回答中显示的内容。
接口:
internal interface IValidatable
{
ErrorProvider ErrorProvider {get;}
}
分机 class:
internal static class IValidatableExtensions
{
internal void ShowValidationResult(this IValidatable self, ValidationResult result)
{
// Here you can use self.ErrorProvider to show your results
}
}
现在您可以让您的表单和用户控件实现 IVilidatable
接口,并且在验证 class 中只需调用 ShowValidationResult
方法。
同样,我会简单地向验证实例发送对 errorProvider 的引用,正如 Olivier 在他的回答中所展示的那样,但这种技术在其他情况下可能会有用,所以我想我最好自己添加一个答案。