Reputation: 2475
I want to make an IEnumerable<TSource>
extension that can convert itself to a IEnumerable<SelectListItem>
. So far I have been trying to do it this way:
public static
IEnumerable<SelectListItem> ToSelectItemList<TSource, TKey>(this
IEnumerable<TSource> enumerable, Func<TSource, TKey> text,
Func<TSource, TKey> value)
{
List<SelectListItem> selectList = new List<SelectListItem>();
foreach (TSource model in enumerable)
selectList.Add(new SelectListItem() { Text = ?, Value = ?});
return selectList;
}
Is this the right way to go about doing it? If so how do I draw the values from the appropriate values from the Func<TSource, TKey>
?
Upvotes: 15
Views: 2187
Reputation: 37780
You're re-inventing the wheel. It is what Enumerable.Select intended for.
EDIT BY @KeithS: To answer the question, if you want this output, you can define an extension method wrapping Enumerable.Select:
public static IEnumerable<SelectListItem> ToSelectItemList<TSource>(
this IEnumerable<TSource> enumerable,
Func<TSource, string> text,
Func<TSource, string> value)
{
return enumerable.Select(x=>new SelectListItem{Text=text(x), Value=value(x));
}
Upvotes: 26
Reputation: 106916
You just need to use the two functions you supply as parameters to extract the text and the value. Assuming both text and value are strings you don't need the TKey
type parameter. And there is no need to create a list in the extension method. An iterator block using yield return
is preferable and how similar extension methods in LINQ are built.
public static IEnumerable<SelectListItem> ToSelectItemList<TSource>(
this IEnumerable<TSource> enumerable,
Func<TSource, string> text,
Func<TSource, string> value)
{
foreach (TSource model in enumerable)
yield return new SelectListItem { Text = text(model), Value = value(model) };
}
You can use it like this (you need to supply the two lambdas):
var selectedItems = items.ToSelecListItem(x => ..., x => ...);
However, you could just as well use Enumerable.Select
:
var selectedItems = items.Select(x => new SelectListItem { Text = ..., Value = ... });
Upvotes: 15
Reputation: 651
Other solutions work as well, but I think that the one from Martin Liversage is the best way to do it:
IEnumerable<SelectListItem> selectListItems = items.Select(x =>
new SelectListItem
{
Text = x.TextProperty,
Value = x.ValueProperty
});
Upvotes: 0
Reputation: 3542
You're on the right path.
Funcs are methods stored in variables, and are invoked like normal methods.
public static IEnumerable<SelectListItem> ToSelectItemList<TSource, TKey>(
this IEnumerable<TSource> enumerable,
Func<TSource, TKey> text,
Func<TSource, TKey> value)
{
List<SelectListItem> selectList = new List<SelectListItem>();
foreach (TSource model in enumerable)
{
selectList.Add(new SelectListItem()
{
Text = text(model),
Value = value(model)
});
}
return selectList;
}
If I might recommend, your Funcs should be Func<TSource, string>
as the text and value are strings in the SelectListItem.
Edit Just thought of this...
Also you don't have to create an inner list but can do a yield return instead. Below is my "optimized" version of your method.
public static IEnumerable<SelectListItem> ToSelectItemList<TSource>(
this IEnumerable<TSource> enumerable,
Func<TSource, string> text,
Func<TSource, string> value)
{
foreach (TSource model in enumerable)
{
yield return new SelectListItem()
{
Text = text(model),
Value = value(model)
};
}
}
Here is the reference for yeild return. It allows you to return the your results as an element in an enumerable, constructing your enumerable invisibly (to you).
http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
Upvotes: 15
Reputation: 65451
A LINQ way of achieving what you want would be:
public static IEnumerable<SelectListItem> ToSelectItemList<TSource, TKey>(
this IEnumerable<TSource> enumerable,
Func<TSource, TKey> textSelector,
Func<TSource, TKey> valueSelector)
{
return from model in enumerable
select new SelectListItem
{
Text = textSelector(model),
Value = valueSelector(model)
};
}
Upvotes: 4
Reputation: 21752
To me it seems like crossing a river to get water. Why not simply use select?
enumerable.Select(item =>
new SelectListItem{
Text = item.SomeProperty,
Value item.SomeOtherProperty
}).ToList();
if you really do want a method then you could do this:
public static
IEnumerable<SelectListItem> ToSelectItemList<TSource, TKey>(this
IEnumerable<TSource> enumerable, Func<TSource, TKey> text,
Func<TSource, TKey> value)
{
return (from item in enumerable
select new SelectListItem{
Text = text(item),
Value = value(item)
}).ToList();
}
Upvotes: 4
Reputation: 28338
Within the body of your extension method, those two parameters are just delegates, and you can run them like any other function:
selectList.Add(new SelectListItem() { Text = text(model), Value = value(model)});
Upvotes: 0