cllpse
cllpse

Reputation: 21727

Generic extension method returning IEnumerable<T> without using reflection

Consider this snippet of code:

public static class MatchCollectionExtensions
{
    public static IEnumerable<T> AsEnumerable<T>(this MatchCollection mc)
    {
        return new T[mc.Count];
    }
}

And this class:

public class Ingredient
{
    public String Name { get; set; }
}

Is there any way to magically transform a MatchCollection object to a collection of Ingredient? The use-case would look something like this:

var matches = new Regex("([a-z])+,?").Matches("tomato,potato,carrot");

var ingredients = matches.AsEnumerable<Ingredient>();


Update

A pure LINQ based solution will suffice as well.

Upvotes: 4

Views: 747

Answers (3)

itowlson
itowlson

Reputation: 74802

Only if you have some way to transform a Match to an Ingredient. Since there isn't a generic way to do this, you'll probably need to give your method a bit of help. For example, your method could take a Func<Match, Ingredient> to perform the mapping:

public static IEnumerable<T> AsEnumerable<T>(this MatchCollection mc, Func<Match, T> maker)
{
  foreach (Match m in mc)
    yield return maker(m);
}

and you could then call this as follows:

var ingredients = matches.AsEnumerable<Ingredient>(m => new Ingredient { Name = m.Value });

You can also bypass creating your own method and just use Select, with the Cast operator to deal with the weak typing of MatchCollection:

var ingredients = matches.Cast<Match>()
                         .Select(m => new Ingredient { Name = m.Value });

Upvotes: 4

Marcelo Cantos
Marcelo Cantos

Reputation: 185852

You could first cast it...

matches.Cast<Match>()

...and then transform the resulting IEnumerable<Match> however you want using LINQ.

Upvotes: 2

Andrew Bezzub
Andrew Bezzub

Reputation: 16032

Try something like this (with System.Linq namespace):

public class Ingredient
{
    public string Name { get; set; }
}

public static class MatchCollectionExtensions
{
    public static IEnumerable<T> AsEnumerable<T>(this MatchCollection mc, Func<Match, T> converter)
    {
        return (mc).Cast<Match>().Select(converter).ToList();
    }
}

and can be used like this:

    var matches = new Regex("([a-z])+,?").Matches("tomato,potato,carrot");

    var ingredients = matches.AsEnumerable<Ingredient>(match => new Ingredient { Name = match.Value });

Upvotes: 2

Related Questions