重构两个将SelectList生成为单个方法的方法

时间:2011-12-27 20:40:27

标签: c# reflection refactoring selectlist

我有以下两种方法从我的数据库中获取数据并返回一个填充的SelectList对象(包括一个“All”选项值),然后我将其传递给我的视图。问题是它们几乎完全相同,除了它们都访问不同的存储库对象并且它们具有不同的ID名称(StatusId和TeamId)。我认为有机会将它们重构为一个接受存储库作为参数的方法,并以某种方式计算出ID名称应该是什么,可能是通过使用反射或某种lambda表达式,但我不知道如何实现这一目标。

private SelectList GetStatusSelectList(int selectedStatusId)
{
  List<MemberStatus> statusList = _memberStatusRepository.All().ToList();
  statusList.Insert(0, new MemberStatus {StatusId = 0, Name = "All"});
  var statusSelectList = new SelectList(statusList, "StatusId", "Name", selectedStatusId);
  return statusSelectList;
}

private SelectList GetTeamSelectList(int selectedTeamId)
{
  List<MemberTeam> teamList = _memberTeamRepository.All().ToList();
  teamList.Insert(0, new MemberTeam { TeamId = 0, Name = "All" });
  var teamSelectList = new SelectList(teamList, "TeamId", "Name", selectedTeamId);
  return teamSelectList;
}

任何人都可以帮助弄清楚如何将这些重构为单一方法吗?

5 个答案:

答案 0 :(得分:3)

嗯,这是我能提出的最通用的,但它需要MemberStatusMemberTeam实施IIdentifiable,我不知道是否可以申请你的情况。如果是这样,这将是要走的路。

private SelectList GetList<T>(IRepository repository, int id, string name)
    where T : IIdentifiable, new()
{
    List<IIdentifiable> list = repository.All().ToList();
    list.Insert(0, new T() { Name = name, Id = id });
    var statusSelectList = new SelectList(list, "Id", "Name", id);
}

接口代码

interface IIdentifiable
{
    int Id { get; set; }
    string Name { get; set; }
}

答案 1 :(得分:2)

您可以尝试以下方法:

private SelectList GetStatusSelectList(int selectedStatusId)
{
    return GetGenericSelectList<MemberStatus>(selectedStatusId, _memberStatusRepository.All().ToList(), "StatusId");
}

private SelectList GetTeamSelectList(int selectedTeamId)
{
    return GetGenericSelectList<MemberTeam>(selectedTeamId, _memberTeamRepository.All().ToList(), "TeamId");
}

private SelectList GetGenericSelectList<T>(int selectedTeamId, List<T> list, string idFieldName) where T : new()
{
    var firstItem = new T();
    (firstItem as dynamic).Name = "All";
    var l = new List<T>(list);
    l.Insert(0, firstItem);
    return new SelectList(l, idFieldName, "Name", selectedTeamId);
}

此解决方案并不理想,并且依赖于某些约定(例如,您的所有项目都应具有Name属性)。然而,这似乎是一个不错的开始。它可以通过使用表达式而不是属性名进一步改进 - 这将允许通过编译时间检查来更改属性名称。

答案 2 :(得分:1)

从我看到的,除了确定要使用的正确存储库之外,将其重构为单个方法的主要障碍是new MemberStatusnew MemberTeam调用。

要想出一个优雅的解决方案,您需要更多的基础架构配置 - 基本上您需要根据类型解析正确的存储库,并且您希望某种工厂构建对象实例。 / p>

以下内容将代码重构为单个方法,但不是(在我看来)比您已有的单独方法更好:

private SelectList GetSelectList<T>(int selectedId, Func<List<T>> repoAllFunc, Func<T> typeNewFunc, string idName)
{
    List<T> list = repoAllFunc();
    list.Insert(0, typeNewFunc());
    var selectList = new SelectList(list, idName, "Name", selectedId);
    return selectList;
}

然后您可以这样称呼它:

var memberStatusSelectList = 
    GetSelectList<MemberStatus>(
        id, 
        () => _memberStatusRepository.All().ToList(),
        () => new MemberStatus {StatusId = 0, Name = "All"});

答案 3 :(得分:1)

你可以疯狂地使用一点界面并执行以下操作:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication3
{

    public class MemberStatus : IDefault<MemberStatus>
    {
        public int StatusId { get; set; }
        public string Name { get; set; }

        public MemberStatus Default
        {
            get { return new MemberStatus() { StatusId = 0, Name = "All" }; }
        }

        public string IdName
        {
            get { return "StatusId"; }
        }
    }

    public class MemberTeam : IDefault<MemberTeam>
    {
        public int TeamId { get; set; }
        public string Name { get; set; }

        public MemberTeam Default
        {
            get { return new MemberTeam() { TeamId = 0, Name = "All" }; }
        }

        public string IdName
        {
            get { return "TeamId"; }
        }
    }

    public interface IDefault<T>
    {
        T Default { get; }
        string IdName { get; }
    }

    public interface IRepository<T>
    {
        IEnumerable<T> All();
    }

    public class MemberStatusRepository : IRepository<MemberStatus>
    {
        public IEnumerable<MemberStatus> All()
        {
            return new[] { 
                new MemberStatus(),
                new MemberStatus()
            };
        }
    }
    public class MemberTeamRepository : IRepository<MemberTeam>
    {
        public IEnumerable<MemberTeam> All()
        {
            return new[] { 
                new MemberTeam(),
                new MemberTeam()
            };
        }
    }

    public class DataAccessLayer
    {
        IRepository<MemberStatus> _memberStatusRepository;
        IRepository<MemberTeam> _memberTeamRepository;
        public DataAccessLayer()
        {
            _memberStatusRepository = new MemberStatusRepository();
            _memberTeamRepository = new MemberTeamRepository();
        }


        public SelectList<TResult> GetTeamSelectList<TRepository, TResult>(TRepository repo, int selectedTeamId)
            where TRepository : IRepository<TResult>
            where TResult : IDefault<TResult>, new()
        {
            List<TResult> teamList = repo.All().ToList();
            var dummyobj = new TResult();
            teamList.Insert(0, dummyobj.Default);
            var teamSelectList = new SelectList<TResult>(teamList, dummyobj.IdName, "Name", selectedTeamId);
            return teamSelectList;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var dal = new DataAccessLayer();
            SelectList<MemberStatus> results = dal.GetTeamSelectList<IRepository<MemberStatus>, MemberStatus>(new MemberStatusRepository(), 5);
            Console.WriteLine();
            Console.Read();
        }
    }

    public class SelectList<TResult>
    {
        public SelectList(List<TResult> teamList, string p, string p_2, int selectedTeamId)
        {

        }
    }

}

如果您可以在界面中定义静态属性会很好,但是因为您不能依赖于创建虚拟对象。

答案 4 :(得分:0)

如果IRepository添加了一些“功能”,您将获得更清晰的代码。

而不是All()有一个SingleRecordsWithAllRecord()方法来处理前两行。然后让存储库定义自己的DataValueFieldDataTextField

private SelectList GetSelectList(IRepository repo, int selectedId)
{
   var selectListAll = repo.SingleRecordsWithAllRecord().ToList();

   return new SelectList(selectListAll, 
                         repo.DataValueField, 
                         repo.DataTextField, 
                         selectedId);
}