在我的应用程序中,我使用条件。我有一个基本的Criteria接口和其他从该基本接口继承的接口:
ICriteria | | ---------------------- | | ITextCriteria IChoices
What I'd like to know is, what is the best way to know what Type the class is?
In my code I have a dropdown box and based on that I have to determine the type:
// Get selected criteria
var selectedCriteria = cmbType.SelectedItem as ICriteria;
if (selectedCriteria is IChoices)
{
//selectedCriteria = cmbType.SelectedItem as IChoices; Doesn't work
IChoices criteria = selectedCriteria as IChoices;//cmbType.SelectedItem as IChoices;
SaveMultipleChoiceValues(criteria);
//_category.AddCriteria(criteria);
}
else
{
//ICriteria criteria = selectedCriteria; //cmbType.SelectedItem as ICriteria;
if (selectedCriteria.GetCriteriaType() == CriteriaTypes.None)
{
return;
}
//_category.AddCriteria(criteria);
}
_category.AddCriteria(selectedCriteria);
selectedCriteria.LabelText = txtLabeltext.Text;
this.Close();
我的问题是,这是最好的方法吗?还是有更好的方法来实现这一目标?
很有可能会有更多基于ICriteria的接口。
编辑:
我有两种类型的控件,我想动态添加到我的应用程序中。一个控件是一个文本框,另一个控件是一个单选按钮。
用户可以为单选按钮定义选项。定义选项后,用户必须选择一个选项,并且所选的选项必须保存在数据库中(以后将用于执行搜索操作)。因此,单击“保存”按钮时,我必须确定所选的类型(单选或文本)并保存答案的可能性(如果是单选)。
对于文本框,这没有任何可能的答案。因此,它具有不同的界面。
我希望现在可以使它更加清晰。这是另一个相关的问题:C# How to implement interface where concrete classes differs?
编辑二:
这是我的方法
SaveMultipleChoiceValues
的样子:private void SaveMultipleChoiceValues(IChoices criteria)
{
foreach (DataGridViewRow row in dgvCriteriaControls.Rows)
{
if (row == dgvCriteriaControls.Rows[dgvCriteriaControls.Rows.Count - 1])
continue;
//multipleChoice.AddChoice(row.Cells["Name"].Value.ToString());
string choice = row.Cells["Name"].Value.ToString();
criteria.AddChoice(choice);
}
}
最佳答案
这看起来是多态性的一个典型例子。
而不是尝试在ICriteria
实现上进行类型切换,为什么不向ICriteria
添加方法(或者可能将虚拟方法添加到所有ICriteria
实现的某些通用基类中),而只是调用它?
显然,此方法的实现将需要访问不属于您的ICriteria
实例的对象,但这是一个问题,您可以根据具体情况使用其他设计模式来解决。
更新:
这是一个完整的解决方案,其中包含您发布的代码:
创建一个新界面ICriteriaView
,该界面对显示Form
的视图(在您的情况下为ICriteria
)进行建模。表单需要根据标准实现的确切接口进行一些处理,因此为代码中存在的每个接口添加一个带有一个重载的方法。不要为ICriteria
本身添加重载。 [1]
interface ICriteriaView {
void ProcessCriteria(IChoices criteria);
void ProcessCriteria(ITextCriteria criteria);
}
您的表单将实现此接口,并提供对
ICriteria
的每个子类型进行适当处理的方法:class MyForm : ICriteriaView {
public void ProcessCriteria(IChoices criteria) {
this.SaveMultipleChoiceValues(criteria);
}
public void ProcessCriteria(ITextCriteria criteria) {
// do nothing
}
private void SaveMultipleChoiceValues(IChoices criteria)
{
foreach (DataGridViewRow row in dgvCriteriaControls.Rows)
{
if (row == dgvCriteriaControls.Rows[dgvCriteriaControls.Rows.Count - 1])
continue;
//multipleChoice.AddChoice(row.Cells["Name"].Value.ToString());
string choice = row.Cells["Name"].Value.ToString();
criteria.AddChoice(choice);
}
}
}
ICriteria
的每个实现都需要实现一个为其类型调用适当的ICriteriaView
重载的方法。这就是发生“重定向魔术”的地方:我们将使用多态性来使编译器“发现”对象的实际ICriteria
类型,然后在ICriteriaView.ProcessCriteria
上使用方法重载来访问适当的代码。interface ICriteria {
void PerformProcessingOn(ICriteriaView view);
}
interface IChoices : ICriteria {
}
interface ITextCriteria : ICriteria {
}
这是向适当的重载进行调度的地方:
class MultipleChoice : IChoices {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
class SimpleInput : ITextCriteria {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
然后,您的代码将执行以下操作:
// Get selected criteria
var selectedCriteria = cmbType.SelectedItem as ICriteria;
// Here's where polymorphism kicks in
selectedCriteria.PerformProcessingOn(this);
// Finally, code that runs the same for all objects
_category.AddCriteria(selectedCriteria);
selectedCriteria.LabelText = txtLabeltext.Text;
this.Close();
保养:
每当您添加新的
ICriteria
子接口实现时,ICriteria
的定义都会强制您在其上实现PerformProcessingOn
方法。在该方法中,您真正可以做的就是调用view.ProcessCriteria(this)
。反过来,这将迫使您在ProcessCriteria
和ICriteriaView
中实现适当的MyForm
重载。结果,我们实现了两个重要目标:
编译器不允许您添加新的
ICriteria
实现,而无需确切指定该实现应如何与ICriteriaView
交互。很容易从源代码中准确地发现
MyView
的作用,例如读取IChoices
的代码时为MultipleChoice
。代码的结构使您“自动”进入MyForm.SaveMultipleChoiceValues
。笔记:
[1]是否为
ICriteria
本身添加重载的选择实际上是一个权衡:如果确实添加一个,则代码如下:
class MultipleChoice : IChoices {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
会始终成功编译,因为即使没有
ICriteriaView.ProcessCriteria(IChoices)
重载,编译器仍然可以使用ICriteriaView.ProcessCriteria(ICriteria)
重载。这意味着,当添加新的
ICriteria
子接口实现时,编译器将不再迫使您检查ICriteriaView.ProcessCriteria(ICriteria)
的实现是否确实为您的新实现做了正确的事情。如果不加,则在编写
view.ProcessCriteria(this);
时,编译器将强制您相应地检查(并更新)ICriteriaView
和MyForm
。在这种情况下,并根据您提供的信息,我认为适当的选择将是最后一个选择。
[2]如上所示,在
ICriteria.PerformProcessingOn
和MultipleChoice
内SimpleInput
的实现看起来完全相同。如果这两个类具有相同的基础(实际上很可能),那么您可能会想将“重复的”代码移入该基础。不要那样做;它将导致解决方案破裂。棘手的是,在
MultipleChoice
内部,当您执行view.ProcessCriteria(this);
时,编译器可以推断this
的静态类型为IChoices
-这就是重定向发生的地方!如果将调用移至假设的基类ProcessCriteria
中的CriteriaBase : ICriteria
,则this
的类型将变为ICriteria
,并且将调用分派到适当的ICriteriaView.ProcessCriteria
重载将不再起作用。
关于c# - C#确定继承接口(interface)类的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4527626/