【问题标题】:How to refactor these 2 similar methods into one?如何将这两种类似的方法重构为一种?
【发布时间】:2009-05-06 08:36:53
【问题描述】:

我见过一些使用“T”来使方法可重用于不同类的通用集合的示例,但我从未真正深入了解或理解这些示例。

我想知道是否可以将以下两种方法合二为一,这样做的缺点是什么(在性能方面)。

有人吗?

        [NonAction]
        public List<SelectListItem> ToSelectList(IEnumerable<Department> departments, string defaultOption)
        {
            var items = departments.Select(d => new SelectListItem() { Text = d.Code + " - " + d.Description, Value = d.Id.ToString() }).ToList();
            items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" });
            return items;
        }

        [NonAction]
        public List<SelectListItem> ToSelectList(IEnumerable<Function> functions, string defaultOption)
        {
            var items = functions.Select(f => new SelectListItem() { Text = f.Description, Value = f.Id.ToString() }).ToList();
            items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" });
            return items;
        }

解决方案

我使用的解决方案:

用法

var departmentItems = departments.ToSelectList(d => d.Code + " - " + d.Description, d => d.Id.ToString(), " - ");
var functionItems = customerFunctions.ToSelectList(f => f.Description, f => f.Id.ToString(), " - ");

 public static class MCVExtentions
    {
        public static List<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, string> text, Func<T, string> value, string defaultOption)
        {
            var items = enumerable.Select(f => new SelectListItem() { Text = text(f), Value = value(f) }).ToList();
            items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" });
            return items;
        }
    }

【问题讨论】:

    标签: c# generics refactoring


    【解决方案1】:

    老派的方法是为部门和职能创建一个通用界面:

    interface A
    {
    int ID{get;}
    string Description{get;}
    }
    

    您对部门实施描述以返回d.Code + " - " + d.Description。 并编写函数来使用这个接口而不是具体的类:

    [NonAction]
        public List<SelectListItem> ToSelectList(IEnumerable<A> as, string defaultOption)
        {
            var items = as.Select(a => new SelectListItem() { Text = a.Description, Value = a.Id.ToString() }).ToList();
            items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" });
            return items;
        }
    

    编辑:关于使用泛型,在这种情况下它不会有太大帮助,因为

    • 您传递的对象需要实现 Id 和 Description
    • 您没有返回这些对象,因此在这方面您不必关心泛型的类型安全

    【讨论】:

    • 当然!谢谢。我一直在思考那些带有“T”的样本,我没有意识到我只需要一个界面。非常感谢。
    • 我想说在这种情况下使用泛型和函数会更好。然后你不必强迫一堆类来实现一个接口。您可能希望在没有 ID 或描述的类上使用该 ToSelectList 函数,并且添加它不是很合乎逻辑(或者例如,描述属性实际上应该被称为其他东西)。
    【解决方案2】:

    如果不实现像@Grzenio 建议的通用接口,您可以使用这样的通用方法:

        public List<SelectListItem> ToSelectList<T>(IEnumerable<T> enumerable, Func<T, string> text, Func<T, string> value, string defaultOption)
        {
            var items = enumerable.Select(f => new SelectListItem() { Text = text(f), Value = value(f) }).ToList();
            items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" });
            return items;
        }
    
        // use like
    
        t.ToSelectList(departments, d => d.Code + " - " + d.Description, d => d.Id.ToString(), "default");
        t.ToSelectList(functions, f => f.Description, f => f.Id.ToString(), "default");
    

    【讨论】:

    • 谢谢!这就是我首先要寻找的。我会尝试实现你的,看看我是否喜欢使用它
    • 嘿,我的答案是相同的,并在此答案前三分钟发布,但此答案获得 3 票,我的票为零! 好吧,无论如何我都会投票赞成,如果只是为了让 Function 的泛型参数按正确的顺序...
    • ToSelectList 也可以作为扩展方法。
    • 对不起,莫蒂,但我发现你的答案不太清楚。由于使用示例,我立即理解了布鲁诺的帖子。现在会投票给你。
    • 我用扩展方法实现了这个,它看起来和感觉都很棒!谢谢大家的帮助。
    【解决方案3】:

    事实上,您可以结合泛型和函数来实现这一点(未经测试甚至可能无法编译)。

    [NonAction]
    public List<SelectListItem> ToSelectList<T>(IEnumerable<T> en, 
                                                Function<string, T> text, 
                                                Function<string, T> value, 
                                                string defaultOption)
    {
        var items = en.Select(x => new SelectListItem() { Text = text(x) , Value = value(x) }).ToList();
        items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" });
        return items;
    }
    

    然后您可以使用适当的 lambda 函数向它分派(或直接调用)。

    [NonAction]
    public List<SelectListItem> ToSelectList(IEnumerable<Department> departments, 
                                             string defaultOption)
    {
        return ToSelectList<Department>(departments, d =>  d.Code + '-' + d.Description, d => d.Id.ToString(), defaultOption);
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-16
      • 2020-09-25
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2012-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多