I have the following class:
public class AuthContext : DbContext
{
public DbSet<Models.Permission> Permissions { get; set; }
public DbSet<Models.Application> Applications { get; set; }
public DbSet<Models.Employee> Employees { get; set; }
// ...
}
I created the extension method Clear()
for type DbSet<T>
. Using reflection I am able to inspect the instance of AuthContext
and read all its properties of type DbSet<T>
as PropertyInfo[
]. How can I cast the PropertyInfo
to DbSet<T>
in order to call the extension method on it ?
var currentContext = new AuthContext();
...
var dbSets = typeof(AuthContext).GetProperties(BindingFlags.Public | BindingFlags.Instance);
dbSets.Where(pi =>
pi.PropertyType.IsGenericTypeDefinition &&
pi.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)).ToList()
.ForEach(pi = ((DbSet<T>)pi.GetValue(currentContext, null)).Clear()); // !!!THIS WILL NOT WORK
Please see Andras Zoltan's answer for an explanation of what you are doing wrong.
However, if you use .NET 4.0, you don't need to use reflection to call the method, you can simply use the new
dynamic
keyword:I changed the cast from
DbSet<T>
todynamic
and changed the way the method is called.Because
Clear
is an extension method, it can't be called directly on thedynamic
type, becausedynamic
doesn't know about extension methods. But as extension methods are not much more than static methods, you can always change a call to an extension method to a normal call to the static method.Everything you have to do is to change
ExtensionClass
to the real class name in whichClear
is defined.You have to do reflection on the DbSet to invoke the Clear Method
Try this :
You can't cast the types because they've got no relationship to each other. You're getting a PropertyInfo which tells you about the type, but is not the type itself.
I think you're going to want to use Type.GetMethod to locate the "Clear" method, as a MethodInfo, and then you'll be able to call MethodInfo.Invoke.
Your cast is wrong.
You can't cast to
(DbSet<T>)
because that's not a concrete type unlessT
is defined inside a generic method or generic type.You have a couple of possibilities.
If DbSet has a base class (e.g.
DbSet_BaseClass
in my code below) from which you can still implement yourClear()
method - then change it's signature from:to:
Then you can change your cast in the
.ForEach
to((DbSet_BaseClass)pi.GetValue...
If you can't do that, you could reflect-invoke the
Clear
extension method by building a specific generic version of it for theT
of theDbSet<T>
:Then, given a property info and context instance:
There are lots of optimisations you can put on top of this, caching delegates etc etc, but this will work.
Update
Or see @Daniel Hilgarth's answer for a cool way to dynamically dispatch the call to the extension method without having to do any of the above (dynamic dispatch effectively does something like the above, but for you with all the caching on top). If it were me - I'd be using that.