C# 如何在运行时将通过反射获取的属性强制转换为正确的泛型类型
简而言之,我要实现的是根据配置验证我(ef core)C# 如何在运行时将通过反射获取的属性强制转换为正确的泛型类型,c#,entity-framework,asp.net-core,.net-core,reflection,C#,Entity Framework,Asp.net Core,.net Core,Reflection,简而言之,我要实现的是根据配置验证我(ef core)DbContext中的特定DbSets。这意味着我希望在配置中指定要验证的表,然后我将对我的DbContext中匹配的DbSet应用验证规则。请允许我解释: 假设配置中有以下值作为JSON数组: "TablesToValidate" : [ "Appointments", "Products" ] 这些值映射到以下各项: public class AppSettin
DbContext
中的特定DbSet
s。这意味着我希望在配置中指定要验证的表,然后我将对我的DbContext
中匹配的DbSet
应用验证规则。请允许我解释:
假设配置中有以下值作为JSON数组:
"TablesToValidate" : [
"Appointments",
"Products"
]
这些值映射到以下各项:
public class AppSettings {
public IEnumerable<DatabaseTable> TablesToValidate { get; set; }
}
下面是DbContext的简化版本:
public DbContext(....)
{
DbSet<Appointment> Appointments { get; set; }
DbSet<Product> Products { get; set; }
DbSet<User> Users { get; set; }
}
正如您所看到的,我想在获取的DbSet上执行的操作是检查它是否为null(如果我将它转换为对象
),以及DbSet.Any()
,这是主要问题
无论我采取什么方法,我仍然需要DbSet的实际泛型类型,以便能够调用DbSet
变量上的Any()
函数。
我无法将运行时类型放入泛型定义
,因为它需要编译时类型。我还尝试将dbSet
变量强制转换为dbSet
,其中BaseEntity
是所有约会
、产品
和用户
的父项,但我怀疑它不起作用,并且会返回null,因为强制转换总是失败的
关于如何解决这个问题,有什么想法吗?尝试转换为非泛型的IEnumerable
。然后可以使用foreach
查看它是否为空
var dbSet = propertyInfo.GetValue(dbContext) as IEnumerable;
bool isEmpty = true;
foreach (var item in dbSet) { isEmpty = false; break; }
您将无法强制转换为“unknown generic”,然后将其作为参数传递给函数。但您可以通过反射调用带有匹配参数的泛型函数。不过看起来不太好看
//首先,我们构造参数的泛型类型,该参数指向AnyAsync。
//myType是给定数据库集的实体类型。
var参数type=typeof(IQueryable)。MakeGenericType(myType);
//其次,我们从EF扩展中提取所需的方法。
//确保得到正确的重载,我们需要一个没有谓词的重载。
var methodInfo=typeof(EntityFrameworkQueryableExtensions)
.GetMethod(名称(EntityFrameworkQueryableExtensions.AnyAsync),
1.
新[]{parameterType,typeof(System.Threading.CancellationToken)})
.MakeGenericMethod(myType);
//使用非类型化参数调用该方法
var结果=等待(任务)方法信息
.Invoke(空,
新对象[]{dbSet,默认值(System.Threading.CancellationToken)});
这是个糟糕的主意。直接从DbSet获取枚举数将导致加载整个表。
appSettings
.TablesToValidate
.ToList()
.Foreach(table => {
var propertyInfo = dbContext //an instance of the DbContext
.GetType()
.GetProperty(table.ToString());
// let's say propertyInfo is not null
var dbSet = propertyInfo.GetValue(dbContext) as DbSet<?>; //Consider this line
if (dbSet is null || !dbSet.Any())
{
//db set not valid. Do Something
}
});
var dbSet = propertyInfo.GetValue(dbContext) as IEnumerable;
bool isEmpty = true;
foreach (var item in dbSet) { isEmpty = false; break; }