我有以下课程:
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; }
// ...
}
我为类型Clear()
创建了扩展方法DbSet<T>
。使用反射我能够检查AuthContext
的实例,并将DbSet<T>
类型的所有属性读作PropertyInfo[
]。如何将PropertyInfo
转换为DbSet<T>
以便在其上调用扩展方法?
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
答案 0 :(得分:4)
请参阅Andras Zoltan的答案,解释你做错了什么。
但是,如果您使用.NET 4.0,则无需使用反射来调用该方法,您只需使用新的dynamic
关键字:
var currentContext = new AuthContext();
var dbSets = typeof(AuthContext).GetProperties(BindingFlags.Public |
BindingFlags.Instance);
dbSets.Where(pi => pi.PropertyType.IsGenericType &&
pi.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
.ToList()
.ForEach(pi => ExtensionClass.Clear((dynamic)pi.GetValue(currentContext,
null)));
我将演员从DbSet<T>
更改为dynamic
并更改了调用方法的方式
由于Clear
是一种扩展方法,因此无法直接在dynamic
类型上调用,因为dynamic
不了解扩展方法。但由于扩展方法不仅仅是静态方法,因此您始终可以将对扩展方法的调用更改为对静态方法的正常调用。
您需要做的就是将ExtensionClass
更改为定义Clear
的真实班级名称。
答案 1 :(得分:1)
你的演员是错的。
您无法转换为(DbSet<T>)
,因为除非在通用方法或泛型类型中定义T
,否则这不是具体类型。
你有几种可能性。
如果DbSet有一个基类(例如我的代码中的DbSet_BaseClass
),您仍然可以从中实现Clear()
方法 - 然后从以下位置更改它的签名:
public static void Clear<T>(this DbSet<T>)
为:
public static void Clear(this DbSet_BaseClass)
然后,您可以在.ForEach
更改为((DbSet_BaseClass)pi.GetValue...
如果你不能这样做,你可以通过为Clear
的{{1}}构建一个特定的通用版本来反映调用T
扩展方法:
DbSet<T>
然后,给定一个属性信息和上下文实例:
MethodInfo myClearMethod = typeof(container_type).GetMethod(
"Clear", BindingFlags.Public | BindingFlags.Static);
您可以在此基础上进行大量优化,缓存代理等等,但这样可行。
或者看看@Daniel Hilgarth对酷方式的回答,即动态地将调用分配给扩展方法而无需执行上述任何操作(动态调度有效地执行上述操作,但对于您而言)所有缓存都在上面)。如果是我 - 我会用它。
答案 2 :(得分:0)
你不能投射类型,因为它们之间没有任何关系。你得到一个PropertyInfo来告诉你类型,但不是类型本身。
我认为您将要使用Type.GetMethod来定位“Clear”方法,作为MethodInfo,然后您将能够调用MethodInfo.Invoke。
答案 3 :(得分:0)
您必须对DbSet进行反射以调用“清除方法”
试试这个:
var dbSets = typeof(AuthContext).GetProperties(BindingFlags.Public | BindingFlags.Instance);
dbSets.Where(pi =>
pi.PropertyType.IsGenericType &&
pi.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)).ToList()
.ForEach(pi =>
{
typeof(DbSet<>)
.MakeGenericType(pi.PropertyType.GetGenericArguments()[0])
.GetMethod("Clear")
.Invoke(pi.GetValue(currentContext, null), null);
}
);