重构具有不同条件的语句

时间:2014-09-10 12:48:37

标签: c# if-statement refactoring

我正在尝试重构一个由多个具有不同条件的if语句组成的方法。 该方法如下所示:

private void DeserializeProperty(object value, 
                                 PropertyInfo property, Format format) {
     if (value == DBNull.Value || value == null) {
        property.SetValue(this, null);
        return;
     }

     if (property.PropertyType == typeof(Id)) {
        SetIdProperty(value, property);
        return;
     }

     if (property.PropertyType.BaseType == typeof(BaseProperty)) {
        SetBaseProperty(value, property);
        return;
     }

     if (property.PropertyType == typeof(Data)) {
        DeserializeData(value, property, format);
        return;
     }

     DeserializeNormalProperty(property, value);
}

用multiorphism替换这些If语句将不起作用(不确定如果它能起作用是否明智)因为条件涉及PropertyType

使用类型为Dictionery<Type,Action<object, PropertyInfo>>的词典替换它们将不起作用 DeserializeData(value, property, format); 不适合行动

此外,上述任何解决方案都不会处理value == DBNull.Value || value == null条件

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

只是一个快速警告 - 以下都不是重构,只是重写你已有的方法。鉴于条件的可变性及其强加的排序(例如基本属性的基本类型优先于数据),很难想象比if-else更好或更清楚的东西。 IMO通过重构一个函数,你无法真正改善你所拥有的东西。但无论如何,我会提出一些可能的重写,以防上诉。

可以使用elses(仅为了便于阅读):

注意:根据一些编码指南,这不如您已有的优先。就个人而言,我觉得它更具可读性。

private void DeserializeProperty(object value, 
                                 PropertyInfo property, Format format) {
    if (value == DBNull.Value || value == null) {
         property.SetValue(this, null);
    }
    else if (property.PropertyType == typeof(Id)) {
         SetIdProperty(value, property);
    }
    else if (property.PropertyType.BaseType == typeof(BaseProperty)) {
         SetBaseProperty(value, property);
    }
    else if (property.PropertyType == typeof(Data)) {
         DeserializeData(value, property, format);
    }
    else {
         DeserializeNormalProperty(property, value);
    }
 }

替代方案(如果你愿意的话)

如果您正在使用类似于此的自定义CleverSwitch类来执行大量类似的切换:

https://stackoverflow.com/a/299120/3940783

可能适合你。它与你对动作词典的想法非常相似 - 但是由于你的条件的变化,让动作没有输入是最干净的,只使用DeserializeProperty范围内的变量而不将它们传递给动作

因此,例如,您可以使用以下内容替换该函数:

private void DeserializeProperty(object value, 
                                 PropertyInfo property, Format format) {
    CleverSwitch.Do(
        CleverSwitch.If(() => value == DBNull.Value || value == null, () => property.SetValue(this, null))
        CleverSwitch.IsType<Id>(property.PropertyType, () => SetIdProperty(value, property)),
        CleverSwitch.IsType<BaseProperty>(property.PropertyType.BaseType, () => SetBaseProperty(value, property)),
        CleverSwitch.IsType<Data>(property.PropertyType, () => DeserializeData(value, property, format)),
        CleverSwitch.Default(() => DeserializeNormalProperty(property,value))
    );
}

CleverSwitch在上述链接上的工作方式与JaredPar的TypeSwitch类似 - 可编码如下:

static class CleverSwitch {
    public class CaseInfo {
        public Func<bool> Condition { get; set; }
        public Action Action { get; set; }
    }

    public static void Do(object source, params CaseInfo[] cases) {
        var type = source.GetType();
        foreach (var entry in cases) {
            if (entry.Condition()) {
                entry.Action();
                break;
            }
        }
    }

    public static CaseInfo IsType<T>(Type T2, Action action) {
        return new CaseInfo() { Condition = () => T2 == typeof(T), Action = action };
    }

    public static CaseInfo If(Func<bool> condition, Action action) {
        return new CaseInfo() { Condition = condition, Action = action };
    }

    public static CaseInfo Default(Action action) {
        return new CaseInfo() { Condition = () => true, Action = action };
    }
}

但总的来说:

在这种情况下,任何帮助你以字典方式重构它的类都必须是相当普遍的,所以基本上只是混淆并增加性能开销。 因此,虽然上面的代码应该可行,但实际上我无法看到它在以下任何方面的if语句中如何改进:

  • 写作时间
  • 可读性
  • 可维护性

事实上,我认为简单的if,return或if,else组合更具可读性,可维护性且更容易直接写出......但这只是我的两分钱!