Mark Lawson
Mark Lawson

Reputation: 329

c# extension method with linq

I want to write an extension method to filter all the people with towns in a people object with the towns in shop object

class people
    string name
    string town

class shops
    string category
    string town

i know i can write

var x = from p in people
        from s in shops
        where p.town == s.town

but i would like to know how to write

var x = from p in people.FilterByTown(p) or FilterByTown(p => p.town) or however it is!!

where FilterByTown is the extension method and all the magic works in there and the object i pass in gets compared with the shop object.

It needs to work with different objects being fed to the method

Hope that all makes sense, the code above is obviously pseudo!

Upvotes: 1

Views: 264

Answers (4)

Blablablaster
Blablablaster

Reputation: 3348

Assuming you have 2 collections people and shops you can write this:

List<People> people = ...
List<Shops> shops = ...

IEnumerable<People> Filter(this IEnumerable<People> people, IEnumerable<Shops> shops){
var result = people.Where(p=>shops.Any(s=>s.town == p.town));
return result;
}

If you want to sort all classes by some arbitrary property you can try this version:

public static IEnumerable<T1> Filter<T1, T2>(
    this IEnumerable<T1> one, 
    IEnumerable<T2> two, string property)
        {
           var result = one.Where(o => two.Any(t =>
               o.GetType().GetProperty(property).
               GetValue(o, null).Equals(t.GetType().
               GetProperty(property).GetValue(t, null))));
           return result;
        }

Of course you need to be sure that property is valid and both objects have it.

Upvotes: 1

YoryeNathan
YoryeNathan

Reputation: 14502

Using reflection, you can filter based on any property of any type:

public static IEnumerable<T> FilterByProperty<T>(this IEnumerable<T> source,
                                                 string property,
                                                 object value)
{
    var propertyInfo = typeof(T).GetProperty(property);

    return source.Where(p => propertyInfo.GetValue(p, null) == value);
}

Usage:

IEnumerable<People> cityPeople = myPeople.FilterByTown("Town", "MyCity");

And if you want a list:

List<People> cityPeopleList = myPeople.FilterByTown("MyCity").ToList();

Upvotes: 2

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112279

You can speed up the queries if you create a list of unique towns

public static class PeopleExtensions
{                             
    private static List<string> _distinctShopTowns;

    private static List<Shop> _shops;
    public static List<Shop> Shops
    {
        get { return _shops; }
        set {
            _shops = value;
            _distinctShopTowns = _shops
                .Select(shop => shop.town)
                .Distinct()
                .ToList();
        } 
    }

    public static IEnumerable<Person> PeopleInTownsWithShops(this IEnumerable<Person> people)
    {
        return people.Where(p => _distinctShopTowns.Contains(p.town));
    }
}

You can call it like this

List<Shop> shops = ...;
List<Person> people = ...;

PeopleExtensions.Shops = shops; // Do every time the shop list changes.

var x = from p in people.PeopleInTownsWithShops();

Upvotes: 0

kongo2002
kongo2002

Reputation: 1024

If I understand your question correctly you want something like this:

public static IEnumerable<People> FilterByTown(this IEnumerable<People> people, IList<Shop> shops)
{
    return people.Where(p => shops.Any(s => s.Town == p.Town));
}

Usage:

peoples.FilterByTown(shops);

Upvotes: 0

Related Questions