Search code examples
c#staticintrospection

determine dynamically which static method to invoke


In my domain model, I have a base entity class from which all classes derive.
I'd like to be able to create filters dynamically based on current user's permissions.
For example- For the Employee class, I would define that an employee can see himself, and his department.
My method would go something like this:

 public static IQueryable<Employee> CreateLinqFilter(IQueryable<Employee> query, User user)
    {
        return query.Where(e => e.Id == user.Id || e.Department.Manager.Id == user.Id);
    }

and then, in my repository base class, I'd like to determine the type dynamically and call the correct CreateLinqFilter method:

protected IQueryable CreateLinq<T>(User user)
    {
        var query = Session.Linq<T>();
        Type t = typeof(T);
        //if not an entity- do not perform filter
        if (!t.IsAssignableFrom(typeof(Entity)))
        {
            return query;
        }
        //now we know that T is a sub-class of Entity. 
        return CreateLinqFilter<T>(query,user);
    }

protected IQueryable CreateLinqFilter<T>(IQueryable<T> query, User user)
        //the following line won't compile:
        //where T: Entity
    {
        //i'd like to be able to do:
        //T.CreateFilter(query);

        //instead, I have to do this?
        if (typeof(T) == Employee)
        {
            return Employee.CreateLinqFilter(query,user);
        }
        if (typeof(T) == Department)
        {
            return Department.CreateLinqFilter(query,user);
        }
        //etc...
    }

The only solution I've got so far is lots of if-else blocks, which are quite unsightly.
anyone got a better idea?
thanks
Jhonny


Solution

  • Try something like:

    return (IQueryable)typeof(T).GetMethod("CreateLinqFilter").Invoke(null, new object[]{query, user});
    

    This uses reflection to find the method at runtime; if this is too slow you may want to consider caching the result of GetMethod somewhere. Note that this method is not restricted to static method; replace the null with a pointer to an object of type T and you can use it on normal instance methods as well.

    For more information, consult the MSDN documentation for the reflection classes; you can find a nice example in the documentation for Invoke.