C# 重构具有不同条件的if语句

C# 重构具有不同条件的if语句,c#,if-statement,refactoring,C#,If Statement,Refactoring,我正在尝试重构一个方法,该方法由具有不同条件的多个if语句组成。 方法如下所示: private void DeserializeProperty(object value, PropertyInfo property, Format format) { if (value == DBNull.Value || value == null) { property.SetValue(this, null)

我正在尝试重构一个方法,该方法由具有不同条件的多个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);
}
用多态性替换这些If语句将不会起作用(不确定如果它起作用是否明智),因为条件与PropertyType有关

使用类型为
Dictionary
的字典替换它们将不起作用,因为该方法
反序列化数据(值、属性、格式)
不适合参加这个活动

此外,上面的非解决方案将处理
value==DBNull.value | | value==null
条件


我该如何解决这个问题呢?

只是一个简单的警告-以下两种都不是重构,只是重写您已经拥有的东西的方法。考虑到条件的可变性质及其强加的顺序(例如basetype of baseproperty优先于数据),很难想出比if-else更好或更清晰的方法。在我看来,仅仅重构一个函数并不能真正改善现有功能。但无论如何,我会提出一些可能的重写,以防任何一方上诉

可以使用ELSE(只是为了可读性): 注意:在一些编码准则下,这比您已经拥有的要少一些。但就我个人而言,我觉得它更具可读性

备选方案(如果您愿意) 如果您正在进行大量类似的切换,请使用与此类似的自定义
CleverSwitch
类:

可能对你有用。这与您关于动作字典的想法非常相似——但是由于您的条件的变化,让动作没有输入,只使用反序列化属性作用域中的变量而不将它们传递到动作中是最干净的

因此,例如,您可以将函数替换为以下内容:

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))
    );
}
private void反序列化属性(对象值,
属性信息属性,格式){
聪明的开关(
CleverSwitch.If(()=>value==DBNull.value | | value==null,()=>property.SetValue(this,null))
CleverSwitch.IsType(property.PropertyType,()=>SetIdProperty(值,属性)),
CleverSwitch.IsType(property.PropertyType.BaseType,()=>SetBaseProperty(value,property)),
IsType(property.PropertyType,()=>反序列化数据(值、属性、格式)),
默认(()=>DeserializeNormalProperty(属性,值))
);
}
其中,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 };
    }
}
静态类克里夫开关{
公共类案例信息{
公共Func条件{get;set;}
公共操作动作{get;set;}
}
公共静态void Do(对象源,参数CaseInfo[]cases){
var type=source.GetType();
foreach(案例中的var条目){
if(entry.Condition()){
entry.Action();
打破
}
}
}
公共静态案例信息IsType(T2类型,动作){
返回新的CaseInfo(){Condition=()=>T2==typeof(T),Action=Action};
}
公共静态案例信息If(函数条件、操作){
返回新的CaseInfo(){Condition=Condition,Action=Action};
}
公共静态案例信息默认值(操作){
返回新的CaseInfo(){Condition=()=>true,Action=Action};
}
}
但总的来说: 在这种情况下,任何帮助您以字典方法重构它的类都必须非常通用,因此本质上只是混淆和增加性能开销。 因此,虽然上述代码应该可以工作,但我真的看不出它在以下任何方面如何改进if语句:

  • 该写了
  • 可读性或
  • 维修性

事实上,我认为简单的if、return或if、else组合更具可读性、可维护性,更易于直接编写。。。但那只是我的两分钱

为什么要使用反射?这个方法的作用是什么?发布小而完整的示例程序。另外,如果你的代码运行良好,它更适合我使用反射,因为这个方法在一个超类中,这样它就适用于从这个超类继承的其他类。不,我仍然不明白你为什么需要反射。发布一个完整的示例(应该编译并运行)。这可能会给你一个更好的答案。我觉得你的方法很好,我不确定它需要多少重构。唯一值得关注的是,您传递了一个输入变量
format
,该变量只在一部分时间内使用。不过,我想说的是,如果
反序列化normalproperty
在您的控制下,则重构它以使其参数反过来(即,
反序列化normalproperty(value,property);
)为了保持一致性,将更好地与其他人配合。(事实上,我想说也许
property,value
更有意义,所以可能是其他方法应该交换它们的参数顺序!)
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 };
    }
}