简体   繁体   中英

IEnumerable Extension

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> ?

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

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

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

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

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

在扩展方法的主体中,这两个参数只是委托,您可以像任何其他函数一样运行它们:

        selectList.Add(new SelectListItem() { Text = text(model), Value = value(model)});

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM