如何将这两个相似的方法重构为一个方法?

5

我看过一些使用“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(), " - ");

with

 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;
        }
    }
3个回答

8

传统的方法是为Department和Function创建一个共同的接口:

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

您需要在部门实现Description接口,以返回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”的示例,没有意识到我只需要一个接口。非常感谢。 - Thomas Stock
2
我认为在这种情况下使用泛型和函数会更好。这样你就不必强制许多类来实现一个接口。你可能想在一个没有ID或描述的类上使用ToSelectList函数,而添加它可能不是很合适(或者例如Description属性应该真正被称为其他名称)。 - Svish

7

如果不像@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");

谢谢!这正是我一开始寻找的。我会尝试实现你的方案,看看是否喜欢使用它。 - Thomas Stock
嘿,我的答案与这个答案完全相同,并且发布时间比这个答案早三分钟,但是这个答案获得了3票,而我的却没有! </sulk> 好吧,无论如何我会给它点赞的,至少因为它将Function的通用参数放在正确的顺序中... - Motti
1
ToSelectList 也可以作为扩展方法实现。 - idursun
对不起,Motti,但我认为你的回答不够清晰。因为有使用示例,我立刻理解了Bruno的帖子。现在我会给你点赞。 - Thomas Stock
我使用扩展方法来实现这个功能,感觉非常不错!谢谢大家的帮助。 - Thomas Stock

4

实际上,您可以通过泛型和函数的组合来实现,类似于以下内容(未经测试可能甚至无法编译)。

[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);

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接