如何删除表达条件

时间:2013-08-27 04:46:17

标签: c# design-patterns

我有一个很长的条件声明:

  public static DataGridColumn CreateAppropreateColumn(string path, PropertyInfo info, string header, IRepository repository)
    {
        DataGridColumn column = null;

        if (info.GetCustomAttributes(typeof(DbComboBoxAttribute), true).Any())
        {
            column = CreateComboBoxColumn(path, info, header, repository);
        }
        else if (info.GetCustomAttributes(typeof(DescribedByteEnumComboBoxAttribute), true).Any())
        {
            column = CreateEnumComboBoxColumn(path, info, header);
        }
        else if (info.GetCustomAttributes(typeof(DropDownLazyLoadingDataGridAttribute), true).Any())
        {
            column = CreateDataGridDropDownLazyLoadingDataGridColumn(path, info, header, repository);
        }
        else if (info.GetCustomAttributes(typeof(DropDownTreeViewAttribute), true).Any())
        {
            column = CreateDataGridTreeViewColumn(path, info, header, repository);
        }
        //Other controls (Like drop down panels ... and so on ) can add here . . .
        //}
        else if (info.GetCustomAttributes(typeof(DatePickerAttribute), true).Any())
        {
            column = CreateDataGridDateColumn(path, info, header);
        }
        else if (info.GetCustomAttributes(typeof(YearPickerAttribute), true).Any())
        {
            column = CreateDataGridYearColumn(path, info, header);
        }
        else if (info.PropertyType == typeof(bool) || info.PropertyType == typeof(bool?))
        {
            column = CreateDataGridCheckBoxColumn(path, info, header);
        }
        else
        {
            column = CreateTextBoxColumn(path, info, header);
        }
return Column;

}

我可以删除ifs吗?

谢谢。

4 个答案:

答案 0 :(得分:3)

我经常这样做的一种方法是创建一个字典,将类型映射到创建结果的函数(您的字典将是Dictionary<Type, Func<string, PropertyInfo, string, IRepository, DataGridColumn>>),然后迭代查找的元素现有属性。

由于在继承链中迭代属性以寻找特定类型的属性是一些工作量,因此迭代它一次以创建属性列表更有意义,然后迭代它并调用适当的功能,如果你在字典中找到一个。只有在字典(或属性)用完后,您才需要拥有if

map = new Dictionary<Type, Func<string, PropertyInfo, string, IRepository, DataGridColumn>>
{
    { typeof(DbComboBoxAttribute), CreateComboBoxColumn }, // no lambda needed if CreateComboBoxColumn already matches our Func<,,,,> type
    { typeof(DescribedByteEnumComboBoxAttribute), (p, i, h, r) => CreateEnumComboBoxColumn(p, i, h) },
    ...
};

然后像这样使用地图:

public static DataGridColumn CreateAppropriateColumn(string path, PropertyInfo info, string header, IRepository repository)
{
    Func<string, PropertyInfo, string, IRepository, DataGridColumn>
        colfunc = null;

    // iterate over all the attributes, looking for one in our dictionary;
    // use Attribute.GetCustomAttributes because it doesn't ignore 'inherit'
    foreach (var attr in Attribute.GetCustomAttributes(info, true))
        if (map.TryGetValue(attr.GetType(), out colfunc))
            return colfunc(path, info, header, repository);

    if (info.PropertyType == typeof(bool) || info.PropertyType == typeof(bool?))
        return CreateDataGridCheckBoxColumn(path, info, header);

    return CreateTextBoxColumn(path, info, header);
}

答案 1 :(得分:1)

我能想到的最少量的代码与Gabes的答案相似,但是映射中的参数信息。

public static DataGridColumn CreateAppropreateColumn(string path, PropertyInfo info, string header, IRepository repository)
{
    //Dictionary of methods to call. Add in all your different column types here with their respective creation functions
    var columnCreationStrategy = new Dictionary<Type, Func<DataGridColumn>>()
        {
            {typeof(DbComboBoxAttribute), () => CreateComboBoxColumn(path,info,header)},
            {typeof(DescribedByteEnumComboBoxAttribute), () => CreateEnumComboBoxColumn(path,info,header, repository)}
        };

    //Just get all attributes here, then return the first successful match
    var attributeList = info.GetCustomAttributes(true).ToList();
    foreach (var attribute in attributeList)
    {
        var type = attribute.GetType();
        if (columnCreationStrategy.ContainsKey(type))
            return columnCreationStrategy[type].Invoke();
    }
    //Maybe throw some exception here? Depends on how you want to handle it. You could even have a default column generation method here
    return null;
}

答案 2 :(得分:0)

我不确定它会更好,但你会使用三元运算符:

DataGridColumn column = info.GetCustomAttributes(typeof(DbComboBoxAttribute), true).Any()
        ? CreateComboBoxColumn(path, info, header, repository)
    : info.GetCustomAttributes(typeof(DescribedByteEnumComboBoxAttribute), true).Any()
        ? CreateEnumComboBoxColumn(path, info, header)
    : info.GetCustomAttributes(typeof(DropDownLazyLoadingDataGridAttribute), true).Any()
        ? CreateDataGridDropDownLazyLoadingDataGridColumn(path, info, header, repository)
    : info.GetCustomAttributes(typeof(DropDownTreeViewAttribute), true).Any()
    ...
        : CreateTextBoxColumn(path, info, header);

基本形式是

value = condition ? valueIfTrue : valueIfFalse;

它可以被链接:

value = condition ? valueIfTrue : condition2 ? valueIfCond2True : valueIfBothFalse

虽然我听说它说三元运算符是为了混淆贫困的comp-sci学生而发明的。在这种情况下,我不确定它是否更清楚。

答案 3 :(得分:0)

我通常收集所有的东西然后循环:

    public static DataGridColumn CreateAppropreateColumn(string path, PropertyInfo info, string header, IRepository repository)
    {
        var criteria = new Dictionary<Type, Func<string, PropertyInfo, string, IRepository, DataGridColumn>>();

        criteria.Add(typeof(DbComboBoxAttribute), CreateComboBoxColumn);
        criteria.Add(typeof(DescribedByteEnumComboBoxAttribute)), CreateEnumComboBoxColumn);
        criteria.Add(typeof(DropDownLazyLoadingDataGridAttribute), CreateDataGridDropDownLazyLoadingDataGridColumn);
        // add more here - in the order you desired...            

        // loop through and return out if there is a matched one
        foreach (Type t in criteria.Keys)
        {
            if (info.GetCustomAttributes(t, true).Any())
            {
                return criteria[t].Invoke(path, info, header, repository);
            }
        }

        // Default Return here:
        return CreateTextBoxColumn(path, info, header);
    }

编辑: 没有看到Gabe的答案,看起来更优雅。