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?
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; }
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With