C# 对于从不同控件类中提取值,使用许多if和重复逻辑重构代码的最佳方法是什么
我在WPF应用程序中有以下代码C# 对于从不同控件类中提取值,使用许多if和重复逻辑重构代码的最佳方法是什么,c#,design-patterns,refactoring,C#,Design Patterns,Refactoring,我在WPF应用程序中有以下代码 if (panel != null) { IList listOfValues = new ComparableListOfObjects(); var childControls = panel.GetChildren<Control>(x => x.Visibility == Visibility.Visible); foreach (Control childControl in childControls)
if (panel != null)
{
IList listOfValues = new ComparableListOfObjects();
var childControls = panel.GetChildren<Control>(x => x.Visibility == Visibility.Visible);
foreach (Control childControl in childControls)
{
var textBox = childControl as TextBox;
if (textBox != null)
{
listOfValues.Add(textBox.Text);
continue;
}
var comboBox = childControl as ComboBox;
if (comboBox != null)
{
listOfValues.Add(comboBox.SelectedItem);
continue;
}
var datePicker = childControl as DatePicker;
if (datePicker != null)
{
listOfValues.Add(datePicker.SelectedDate.GetValueOrDefault());
continue;
}
var numericBox = childControl as NumericUpDown;
if (numericBox != null)
{
listOfValues.Add(numericBox.Value);
continue;
}
}
在其他方法中的同一类中有相同的代码
private static object GetControlValue(Control control)
{
if (control == null)
throw new ArgumentNullException("control");
var textBox = control as TextBox;
if (textBox != null)
return textBox.Text;
var comboBox = control as ComboBox;
if (comboBox != null)
return comboBox.SelectedValue;
var datePicker = control as DatePicker;
if (datePicker != null)
return datePicker.SelectedDate.GetValueOrDefault();
var numericUpDown = control as NumericUpDown;
if (numericUpDown != null)
return numericUpDown.Value;
throw new NotSupportedException();
}
也许我应该使用策略设计模式,但在这种情况下,我需要为每种类型的控件创建额外的类
你能给我推荐这个问题更好的解决方案吗?
提前感谢。您可以使用这样的方法,依赖于
is
:
private static object GetControlValue(Control control)
{
if (control == null)
throw new ArgumentNullException("control");
if (control is TextBox) return (control as TextBox).Text;
if (control is ComboBox) return (control as ComboBox).SelectedValue;
...
}
及
if(面板!=null)
{
IList listOfValues=新的可比ListofObject();
var childControls=panel.GetChildren(x=>x.Visibility==Visibility.Visible);
foreach(childControls中的Control childControl)
{
if(childControl是TextBox){listOfValues.Add((childControl作为TextBox.Text);continue;}
if(childControl是组合框){listOfValues.Add((childControl作为组合框).SelectedValue);continue;}
...
}
}
第二个块中的
continue
可能甚至不需要,但这需要一些测试。我相信您正在寻找。每个控制器一个类是一种方法,但引用参考文章:
注意:此模式的更灵活的方法是创建包装器
类实现定义accept方法的接口。这个
包装器包含一个指向CareElement的引用,该引用可以是
通过构造函数初始化。这种方法避免了
在每个元素上实现一个接口。[参见Java Tip 98文章]
[下文第条]
你也许可以摆脱这个问题。如果
和开关语句不是坏事的话。即使做一些基本的类型检查也不一定是坏事,特别是当使用的类型不能多态使用时。让这种逻辑表达不止一次是不可取的,因为你在重复你自己,而且你对同一个变化有多个维护点
在原始代码段中,您可以
var blah = obj as Foo;
if (blah != null)
{
someList.Add(blah.Value);
}
并对多个控件类型重复此操作。但是在以后的私有方法中,基本上相同的逻辑表达了相同的次数
var blah = obj as Foo;
if (blah != null)
return blah.Value;
唯一的区别是,在第一个代码段中,您获取值并将其添加到列表中。在第二步中,返回值。第一个代码段应该去掉它的类型检查逻辑,它应该使用另一个方法中已经表达的逻辑
foreach (var control in childControls)
{
listOfValues.Add(GetControlValue(control));
}
想法是不要重复你自己。干式。有点麻烦,但这里有一种使用委托和集合初始值设定项来消除冗余的方法(您可能不喜欢按原样使用,而是按想法使用)
首先创建一个如下所示的类:
// Needs argument validation. Also, extending Dictionary<TKey, TValue>
// probably isn't a great idea.
public class ByTypeEvaluator : Dictionary<Type, Func<object, object>>
{
public void Add<T>(Func<T, object> selector)
{
Add(typeof(T), x => selector((T)x));
}
public object Evaluate(object key)
{
return this[key.GetType()](key);
}
}
您可以将其作为通用方法中的案例选择来执行,但此样式仍有一些工作要做:
public static string GetValue<T>(T obj) where T:Control
{
switch (obj.GetType().ToString())
{
case "TextBox":
return (obj as TextBox).Text;
break;
case "ComboBox":
return (obj as ComboBox).SelectedValue.ToString();
break;
//..etc...
}
}
公共静态字符串GetValue(T obj),其中T:Control
{
开关(obj.GetType().ToString())
{
案例“文本框”:
返回(obj作为文本框)。文本;
打破
案例“组合框”:
返回(对象作为组合框)。SelectedValue.ToString();
打破
//……等等。。。
}
}
看一看:@Ray感谢您的建议如果这是一个更复杂的逻辑,我可能会建议类似责任链的东西,但在这种情况下,演员阵容就可以了。您可以更改此语句var childControls=panel.GetChildren(x=>x.Visibility==Visibility.Visible);对于类型为的select语句,然后有一个helper类,每个控件都有很多方法。据我所知,下面我建议的方法最接近于“删除”它们(事实上,您没有…)。我看到的唯一替代方法是编写一个包含大量代码的包装器对象,以映射要提取的字段以及每个字段的内部属性。这需要大量的思考。请检查此Thaks以获得答案,但if(控件是类名)的重复项没有删除。请参阅问题本身下的我的评论以了解详细信息。我无法想象在这种情况下如何应用它。一些代码示例,please@Hohhi我还没有弄清楚细节。该模式“允许在不修改类本身的情况下向类族添加新的虚拟函数”。OP基本上是想在Control
类中添加一个虚拟函数GetControlValue
。该模式是关于遍历某个IMHO或我不知道其所有应用程序的对象。它从您访问您的方式中抽象出访问时执行的操作。。。他们非常聪明。但是,伙计,这真的比手工操作这四个控件简单吗感谢您的回答,在这种情况下,如果无法将GetControlValue方法转换为适当类型的控件,则会引发异常,但当我们在childControls集合中循环时,此集合可以包含无法转换的控件,例如ScrollViewer,并且我们不需要引发异常,只需跳过此控件即可。在这种情况下会怎么样?@Serghei,在这种情况下,我将重构并将异常抛出机制与值查找机制分离。需要发生异常的调用可以调用X()
,而X
调用Y()
。不需要异常的调用方可以直接调用Y()
X()
将引发异常,但将值查找逻辑本身委托给Y()
,这可能会为不受支持的控件类型返回null。感谢您的回答,想法很清楚,但如果属性的值也将为null,则方法Y()可以返回null,如果控件类型不受支持或属性值为null,如何解决此问题?@Serghei,这是另一个问题,我同意。我可以这样做。这可能是个坏主意,有点像坐在我的座位上。当继续时,为默认操作传入一个Func
// Needs argument validation. Also, extending Dictionary<TKey, TValue>
// probably isn't a great idea.
public class ByTypeEvaluator : Dictionary<Type, Func<object, object>>
{
public void Add<T>(Func<T, object> selector)
{
Add(typeof(T), x => selector((T)x));
}
public object Evaluate(object key)
{
return this[key.GetType()](key);
}
}
// Give this variable longer lifetime if you prefer.
var map = new ByTypeEvaluator
{
(ComboBox c) => c.SelectedItem,
(TextBox t) => t.Text,
(DateTimePicker dtp) => dtp.Value,
(NumericUpDown nud) => nud.Value
};
Control myControl = ...
var myProjection = map.Evaluate(myControl);
public static string GetValue<T>(T obj) where T:Control
{
switch (obj.GetType().ToString())
{
case "TextBox":
return (obj as TextBox).Text;
break;
case "ComboBox":
return (obj as ComboBox).SelectedValue.ToString();
break;
//..etc...
}
}