C# 将PropertyInfo强制转换为泛型类型

C# 将PropertyInfo强制转换为泛型类型,c#,generics,reflection,casting,C#,Generics,Reflection,Casting,我有以下课程: 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; }

我有以下课程:

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; } 
    // ...
}

您不能强制转换类型,因为它们彼此没有关系。您将获得一个PropertyInfo,它告诉您类型,但不是类型本身

我想您应该使用Type.GetMethod来定位“Clear”方法,作为MethodInfo,然后您将能够调用MethodInfo.Invoke。

您的强制转换是错误的

不能强制转换到
(DbSet)
,因为这不是一个具体的类型,除非在泛型方法或泛型类型中定义了
t

你有两种可能

如果DbSet有一个基类(例如下面我的代码中的
DbSet\u BaseClass
),您仍然可以从该基类实现
Clear()
方法,则将其签名更改为:

public static void Clear<T>(this DbSet<T>)
然后您可以将
.ForEach
中的强制转换更改为
((DbSet\u BaseClass)pi.GetValue…

如果您不能这样做,您可以通过为
DbSet
t
构建一个特定的泛型版本来调用
Clear
扩展方法:

然后,给定属性信息和上下文实例:

Type propType = pi.PropertyType;
Type typeofT = propType.GetGenericArguments[0];
MethodInfo toInvoke = myClearMethod.MakeGenericMethod(typeofT);
//now invoke it
toInvoke.Invoke(null, new[] { pi.GetValue(currentContext, null) });
有很多优化,你可以放在上面,缓存代理等,但这将工作

更新
或者查看@Daniel Hilgarth的答案,了解一种很酷的方法,可以动态地将调用分派到扩展方法,而不必执行上述任何操作(动态分派可以有效地执行类似于上述的操作,但对于您来说,所有缓存都位于顶部)。如果是我-我会使用它。

您必须在DbSet上进行反射才能调用Clear方法

试试这个:

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);
                      }
                      );
var dbSets=typeof(AuthContext).GetProperties(BindingFlags.Public | BindingFlags.Instance);
其中(pi=>
pi.PropertyType.IsGenericType&&
pi.PropertyType.GetGenericTypeDefinition()==typeof(DbSet)).ToList()
.ForEach(pi=>
{
类型(数据库集)
.MakeGenericType(pi.PropertyType.GetGenericArguments()[0])
.GetMethod(“清除”)
.Invoke(pi.GetValue(currentContext,null),null);
}
);

请参阅安德拉斯·佐尔坦的答案,了解您做错了什么

但是,如果使用.NET 4.0,则无需使用反射来调用该方法,只需使用新的
动态
关键字:

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)));
var currentContext=new AuthContext();
var dbSets=typeof(AuthContext).GetProperties(BindingFlags.Public)
BindingFlags.Instance);
其中(pi=>pi.PropertyType.IsGenericType&&
pi.PropertyType.GetGenericTypeDefinition()==typeof(DbSet))
托利斯先生()
.ForEach(pi=>ExtensionClass.Clear((动态)pi.GetValue(currentContext,
空);;
我将强制转换从
DbSet
更改为
dynamic
,并更改了方法的调用方式。
因为
Clear
是一种扩展方法,所以不能直接在
dynamic
类型上调用它,因为
dynamic
不知道扩展方法。但是由于扩展方法并不比静态方法多得多,所以您始终可以将对扩展方法的调用更改为对静态方法的普通调用。

你所要做的一切就是将
ExtensionClass
更改为定义
Clear
的真实类名。

当你说
!!!这行不通
你到底是什么意思?发生了什么事你可以发布
Clear()的签名(不需要正文)
帮助@Daniel Hilgarth和我澄清一些事情的方法:)我想知道
pi.PropertyType.IsGenericTypeDefinition
如何在你身上不失败。请看,他正在使用GetValue从PropertyInfo获取实例。这不是问题,因为他没有尝试强制转换
pi
,而是
pi.GetValue
的结果。(@Andras:我知道你说了同样的话,但我想重新措辞,因为我一开始不理解你的评论…;-)@Daniel Hilgarth-没问题:)一个优化方法是使用
动态
。您可能想添加一个示例。@Daniel Hilgarth-啊,是的;有时我仍然会在DIY动态绑定中思考:)@Daniel Hilgarth-事实上,想不想提出另一个解决方案来说明如何看待
动态
工作?我考虑过
dynamic
的情况,但是很难找到一个好的方法将
extnMethod(这是一个)
转换为
dynamic
,这样就不需要在扩展方法中进行反射了!我遗漏了一些我想的东西,看看我的答案。这应该可以做到。我还考虑创建非通用版本
publicstaticvoidclear(这个DbSet集)
,然后是行
。ForEach(pi=((DbSet)pi.GetValue(currentContext,null)).Clear()为我提供无效的强制转换异常(无法将DbSet强制转换为DbSet)。但是,这一行正在工作:
DbSet testCastEmp=(DbSet)currentContext.Employees
。我遗漏了什么吗?这是一个扩展方法,因此他无法从
DbSet
类型和
.Invoke
it@Daniel希尔加思-尼斯;但是如果
Clear
是一种扩展方法,那么这种方法会起作用吗?运行Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:“Tests.a”不包含“Clear”的定义
。它当然适用于实例方法。您也不能将扩展显式地作为静态调用,因为它可能是
Clear
,需要一个泛型参数。实际上,也许我们需要OP@Andras:啊。。。我错过了。更正。@Daniel Hilgarth-是的;然后我编辑了我的评论(即
Type propType = pi.PropertyType;
Type typeofT = propType.GetGenericArguments[0];
MethodInfo toInvoke = myClearMethod.MakeGenericMethod(typeofT);
//now invoke it
toInvoke.Invoke(null, new[] { pi.GetValue(currentContext, null) });
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);
                      }
                      );
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)));