Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactor two methods that generate a SelectList into a single method

I have the following two methods that get data from my DB and return a populated SelectList object (including an "All" option value) that I then pass onto my view. The problem is that they are almost identical with the exception that they both access different repository objects and they have different ID names (StatusId and TeamId). I think there is an opportunity to refactor them into a single method that accepts the repository as a parameter and somehow figures out what the ID name should be, perhaps by using reflection or some sort of lambda expression, but I don't know quite how to accomplish this.

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;
}

Can anyone help figure out how to refactor these into a single method?

like image 307
bigmac Avatar asked Dec 27 '11 20:12

bigmac


3 Answers

Well, this is the most generic I can come up with, but it will require that your MemberStatus and MemberTeam implement IIdentifiable, which I don't know if can apply to your case. If so, this would be the way to go.

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

And the interface code

interface IIdentifiable
{
    int Id { get; set; }
    string Name { get; set; }
}
like image 55
Tomislav Markovski Avatar answered Nov 16 '22 10:11

Tomislav Markovski


you may try the following:

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

This solution is not ideal and relies on some conventions (e.g. all your items should have Name property). However it seems to be a not bad way to start with. It may be improved further by using Expressions instead of property names -- that would allow to change property names with compile time check.

like image 22
the_joric Avatar answered Nov 16 '22 10:11

the_joric


You can go a little interface crazy and do the following:

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

        }
    }

}

It would be nice if you could define static properties in an interface, but since you can't I rely on creating a dummy object instead.

like image 1
foson Avatar answered Nov 16 '22 09:11

foson