Kiada Kiada - 4 years ago 122
C# Question

Creating a generic select list generating method of type T

I was wondering how I might be able to create a re-usable method that creates select lists based on method arguments? I was thinking something like below:

public IEnumerable<SelectListItem> CreateSelectList(IList<T> entities, T value, T text)
{

return entities
.Select(x => new SelectListItem
{
Value = x.value.ToString(),
Text = x.text.ToString()
});
}


I think I have it a bit backwards though. I'm unsure how to call a method like this, when I call it with an IList of Category for the first argument the compiler complains that it cannot assign type Category to type T? Also, how would I insert the method arguments into the lambda? Any help appreciated!

Code I'm trying to use to call it (which is wrong, but you get the idea)

viewModel.Categories = _formServices.CreateSelectList(categories, Id, Name);


Code I'm trying to make more generic and reusable:

viewModel.Categories = categories
.Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
});


Edit For Answer

Credit goes to @Pavel Backshy for working answer. I wanted to edit in an extension I made to his answer in case it helps anybody! The extension just adds a .Where clause into the mix:

public IEnumerable<SelectListItem> CreateSelectListWhere<T>(IList<T> entities, Func<T, bool> whereClause, Func<T, object> funcToGetValue, Func<T, object> funcToGetText)
{
return entities
.Where(whereClause)
.Select(x => new SelectListItem
{
Value = funcToGetValue(x).ToString(),
Text = funcToGetText(x).ToString()
});
}

Answer Source

You can define this using Reflection to take property value by name, but I think more elegant and flexible to use Func. Change your method to:

public IEnumerable<SelectListItem> CreateSelectList<T>(IList<T> entities, Func<T, object> funcToGetValue, Func<T, object> funcToGetText)
{
    return entities
            .Select(x => new SelectListItem
            {
                Value = funcToGetValue(x).ToString(),
                Text = funcToGetText(x).ToString()
            });
}

And then you can use it by this way:

viewModel.Categories = _formServices.CreateSelectList(categories, x => x.Id, x => x.Name);
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download