views:

83

answers:

1

Hi all,

I'm trying to build a utility method using Linq that will help me with a common Linq-to-Objects search.

I have a PropertyTbl object which has a reference to an Address. I have a IEnumerable<PropertyTbl>. I have written a helper that takes an IEnumerable<Address> and some search criteria returns an IEnumerable<Address> which when iterated will give me the matching addresses.

However I can't figure out how to plug the two together because although I can do a .Select() on my IEnumerable<PropertyTbl> to get the address enumerable I need the result to be IEnumerable<PropertyTbl>.

Here's my helper code

    public static IEnumerable<Address> BuildAddressWhereClause(IEnumerable<Address> addresses, string value, AddressSearchOptions options)
    {
        string search = value.ToUpper();

        if ((options & AddressSearchOptions.Address1To4) == AddressSearchOptions.Address1To4)
        {
            addresses = addresses.Where(o => o.Address1.ToUpper().Contains(search)
                                             || o.Address2.ToUpper().Contains(search)
                                             || o.Address3.ToUpper().Contains(search)
                                             || o.Address4.ToUpper().Contains(search));
        }

        if ((options & AddressSearchOptions.City) == AddressSearchOptions.City)
        {
            addresses = addresses.Where(o => o.City.ToUpper().Contains(search));
        }

        if ((options & AddressSearchOptions.PostCode) == AddressSearchOptions.PostCode)
        {
            addresses = addresses.Where(o => o.PostCode.ToUpper().Contains(search));
        }

        return addresses;
    }

and what I want to do is this.

IEnumerable<PropertyTbl> properties = ...;

IEnumerable<PropertyTbl> filteredProperties = <use my address helper somehow>;

// this works but I need the properties as the result not just the addresses
IEnumerable<Address> filteredAddresses = AddressUtils.FilterAddresses(properties.Select(o => o.Address), "1 High Street", ...);

I can do what I want by putting the helper code directly into the code where properties are being loaded/filtered but then I can't reuse it.

Any suggestions appreciated.

+2  A: 

An IEnumerable<PropertyTbl> is not an IEnumerable<Address>, so you need some way of getting to the Address field of a PropertyTable (unless you change your BuildAddressWhereClause to take an IEnumerable<PropertyTbl>.

Something like this should do the trick:

public static IEnumerable<T> BuildAddressWhereClause<T>(IEnumerable<T> source, string value, AddressSearchOptions options, Func<T, Address> addressExtractor) { 
    string search = value.ToUpper(); 

    if ((options & AddressSearchOptions.Address1To4) == AddressSearchOptions.Address1To4) { 
        source = source.Where(o => addressExtractor(o).Address1.ToUpper().Contains(search) 
                                   || addressExtractor(o).Address2.ToUpper().Contains(search) 
                                   || addressExtractor(o).Address3.ToUpper().Contains(search) 
                                   || addressExtractor(o).Address4.ToUpper().Contains(search)); 
    } 

    if ((options & AddressSearchOptions.City) == AddressSearchOptions.City) { 
        source = source.Where(o => addressExtractor(o).City.ToUpper().Contains(search)); 
    } 

    if ((options & AddressSearchOptions.PostCode) == AddressSearchOptions.PostCode) { 
        source = source.Where(o => addressExtractor(o).PostCode.ToUpper().Contains(search)); 
    } 

    return source; 
} 

And then you invoke it like

IEnumerable<PropertyTbl> properties = ...;      
IEnumerable<PropertyTbl> filteredProperties = AddressUtils.FilterAddresses(properties, "whatever", AddressSearchOptions.Whatever, p => p.Address);
erikkallen
That's the trick I was missing, thanks!
Mike Q