Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对于从不同控件类中提取值,使用许多if和重复逻辑重构代码的最佳方法是什么_C#_Design Patterns_Refactoring - Fatal编程技术网

C# 对于从不同控件类中提取值,使用许多if和重复逻辑重构代码的最佳方法是什么

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)

我在WPF应用程序中有以下代码

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...
            }   
        }