[英]Cast a property to its actual type dynamically using reflection (where actual type is generic)
[英]How to cast down a property fetched with reflection to a its correct generic type at runtime
简而言之,我要实现的是根据配置在我的(ef 核心) DbContext
中验证特定的DbSet
。 这意味着我想在配置中指定我想要验证的表,然后我会将验证规则应用于我的DbContext
DbSet
请允许我解释一下:
假设您在配置中有以下值作为 JSON 数组:
"TablesToValidate" : [
"Appointments",
"Products"
]
这些值映射到以下内容:
public class AppSettings {
public IEnumerable<DatabaseTable> TablesToValidate { get; set; }
}
其中DatabaseTable
是一个 Enum,所有表名都作为 Enum 值:
[JsonConverter(typeof(StringEnumConverter))]
public enum DatabaseTable {
Appointments,
Products,
Users
}
这是 DbContext 的简化版本:
public DbContext(....)
{
DbSet<Appointment> Appointments { get; set; }
DbSet<Product> Products { get; set; }
DbSet<User> Users { get; set; }
}
应该发生的是,对于从配置中获取的每个DatabaseTable
,我需要从DbSet
中获取与其名称匹配的DbContext
并验证它不为空。 这是我到目前为止的代码以及我遇到的问题:
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
}
});
如您所见,我想对获取的DbSet
执行的操作是检查它是否为 null (如果我将其转换为object
将起作用)和dbSet.Any()
这是主要问题。
无论我采取什么路线,我仍然需要 DbSet 的实际泛型类型才能在dbSet
变量上调用Any()
function。 我不能将运行时类型放在通用定义<>
中,因为它需要编译时类型。 我还尝试将dbSet
变量强制转换为DbSet<BaseEntity>
,其中BaseEntity
是所有Appointment
、 Product
和User
的父级,但我怀疑它不起作用并且它将返回 null 因为强制转换总是会失败。
关于如何解决这个问题的任何想法?
您将无法转换为“未知泛型”,然后将其作为参数传递给 function。 但是您可以通过反射调用具有匹配参数的通用 function。 不过看起来不会很漂亮。
// first, we construct the generic type of the parameter that goes to AnyAsync.
// myType is the type of the entity for the given DbSet.
var parameterType = typeof(IQueryable<>).MakeGenericType(myType);
// second, we extract the needed method from the EF extensions.
// make sure to get the correct overload, we need the one without the predicate.
var methodInfo = typeof(EntityFrameworkQueryableExtensions)
.GetMethod(nameof(EntityFrameworkQueryableExtensions.AnyAsync),
1,
new[] { parameterType, typeof(System.Threading.CancellationToken) })
.MakeGenericMethod(myType);
// invoke the method with the untyped parameters
var result = await (Task<bool>)methodInfo
.Invoke(null,
new object[] { dbSet, default(System.Threading.CancellationToken) });
尝试转换为非通用IEnumerable
。 然后,您可以使用foreach
查看它是否为空。
var dbSet = propertyInfo.GetValue(dbContext) as IEnumerable;
bool isEmpty = true;
foreach (var item in dbSet) { isEmpty = false; break; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.