Рефакторинг двух методов, которые генерируют SelectList в один метод - PullRequest
5 голосов
/ 28 декабря 2011

У меня есть два следующих метода, которые получают данные из моей БД и возвращают заполненный объект SelectList (включая значение параметра «Все»), который я затем передаю в свое представление. Проблема заключается в том, что они практически идентичны, за исключением того, что они оба обращаются к разным объектам репозитория и имеют разные имена идентификаторов (StatusId и TeamId). Я думаю, что есть возможность реорганизовать их в единый метод, который принимает хранилище в качестве параметра и каким-то образом выясняет, каким должно быть имя идентификатора, возможно, с помощью отражения или какого-то лямбда-выражения, но я не знаю, как чтобы сделать это.

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 ]

3 голосов
/ 28 декабря 2011

Что ж, это самое общее, что я могу придумать, но для этого потребуется, чтобы ваши MemberStatus и MemberTeam реализовали 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; }
}
2 голосов
/ 28 декабря 2011

Вы можете попробовать следующее:

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). Однако, похоже, это неплохой способ начать. Это может быть улучшено путем использования выражений вместо имен свойств - это позволит изменять имена свойств с проверкой времени компиляции.

1 голос
/ 28 декабря 2011

Вы можете немного помешать интерфейсу и сделать следующее:

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)
        {

        }
    }

}

Было бы неплохо, если бы вы могли определять статические свойства в интерфейсе, но так как вы не можете полагаться на создание фиктивной фигурыобъект вместо.

1 голос
/ 28 декабря 2011

Из того, что я вижу, основными препятствиями на пути рефакторинга этого в один метод являются вызовы new MemberStatus и new MemberTeam, в дополнение к определению подходящего репозитория для использования.

Длячтобы придумать элегантное решение, вам потребуется немного больше сконфигурированной инфраструктуры - в основном вам нужно будет разрешить правильный репозиторий в зависимости от типа, и вам понадобится фабрика для создания экземпляра объекта.

Следующее изменит код в один метод, но (на мой взгляд) не лучше, чем отдельные методы, которые у вас уже есть:

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"});
0 голосов
/ 28 декабря 2011

Если IRepository добавляет несколько «функций», вы получите более чистый код.

Вместо All() есть метод SingleRecordsWithAllRecord(), который обрабатывает первые две строки.Затем пусть хранилище определит свои собственные DataValueField и DataTextField.

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

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