Question

Inspired by the MVC storefront the latest project I'm working on is using extension methods on IQueryable to filter results.

I have this interface;

IPrimaryKey
{
  int ID { get; }
}

and I have this extension method

public static IPrimaryKey GetByID(this IQueryable<IPrimaryKey> source, int id)
{
    return source(obj => obj.ID == id);
}

Let's say I have a class, SimpleObj which implements IPrimaryKey. When I have an IQueryable of SimpleObj the GetByID method doesn't exist, unless I explicitally cast as an IQueryable of IPrimaryKey, which is less than ideal.

Am I missing something here?

Was it helpful?

Solution

It works, when done right. cfeduke's solution works. However, you don't have to make the IPrimaryKey interface generic, in fact, you don't have to change your original definition at all:

public static IPrimaryKey GetByID<T>(this IQueryable<T> source, int id) where T : IPrimaryKey
{
    return source(obj => obj.ID == id);
}

OTHER TIPS

Edit: Konrad's solution is better because its far simpler. The below solution works but is only required in situations similar to ObjectDataSource where a method of a class is retrieved through reflection without walking up the inheritance hierarchy. Obviously that's not happening here.

This is possible, I've had to implement a similar pattern when I designed a custom entity framework solution for working with ObjectDataSource:

public interface IPrimaryKey<T> where T : IPrimaryKey<T>
{
    int Id { get; }
}

public static class IPrimaryKeyTExtension
{
     public static IPrimaryKey<T> GetById<T>(this IQueryable<T> source, int id) where T : IPrimaryKey<T>
     {
         return source.Where(pk => pk.Id == id).SingleOrDefault();
     }
}

public class Person : IPrimaryKey<Person>
{
    public int Id { get; set; }
}

Snippet of use:

var people = new List<Person>
{
    new Person { Id = 1 },
    new Person { Id = 2 },
    new Person { Id = 3 }
};

var personOne = people.AsQueryable().GetById(1);

This cannot work due to the fact that generics don't have the ability to follow inheritance patterns. ie. IQueryable<SimpleObj> is not in the inheritance tree of IQueryable<IPrimaryKey>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top