考虑以下模型(.NET 8、C# 12):
public partial interface IEntity
{
public long Id { get; set; }
}
public partial interface IEntity<TEntity>
where TEntity : class, IEntity, IEntity<TEntity>, new()
{
}
public partial class User: IEntity, IEntity<User>
{
public long Id { get; set; }
}
public partial class Currency: IEntity, IEntity<Currency>
{
public long Id { get; set; }
}
public partial class ApplicationDbContext: DbContext
{
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Currency> Currencies { get; set; }
//// TODO: Fix to get a list of DbSets.
//public static List<object> GetDbSets () => typeof(ApplicationDbContext)
// .GetProperties(BindingFlags.Instance | BindingFlags.Public)
// .Where(p => p.CanRead && p.CanWrite)
// .Where(p => p.GetGetMethod(nonPublic: false) != null)
// .Where(p => p.GetSetMethod(nonPublic: false) != null)
// .Where(p => p.PropertyType == typeof(DbSet<>))
// .Cast<object>()
// .ToList();
//// TODO: Fix to get a list of entities.
//public static List<Type> GetEntities () => typeof(ApplicationDbContext)
// .GetProperties(BindingFlags.Instance | BindingFlags.Public)
// .Where(p => p.CanRead && p.CanWrite)
// .Where(p => p.GetGetMethod(nonPublic: false) != null)
// .Where(p => p.GetSetMethod(nonPublic: false) != null)
// .Where(p => p.PropertyType.IsGenericType)
// .Where(p => p.PropertyType.Name.StartsWith(typeof(DbSet<>).Name))
// //.Where(p => p.PropertyType == typeof(DbSet<IEntity>))
// .Select(p => p.PropertyType.GetGenericArguments() [0])
// //.Cast<object>()
// .ToList();
public static List<Type> GetEntityTypesOrderedDelete () => new []
{
typeof(User),
typeof(Account),
typeof(Transaction),
typeof(AccountCategory),
typeof(Currency),
}
.ToList();
}
private static void Main ()
{
}
我想使用以下标准获取属性
List<System.Reflection.PropertyInfo>
值的列表:
DbSet<IEntity<TEntity>>
。Dbset
属性必须只有一个通用参数 IEntity<TEntity>
。IEntity<TEntity>
必须恰好有一个嵌套泛型参数 TEntity
。TEntity
必须遵守 IEntity<TEntity>
强制执行的泛型类型约束。ApplicationDbContext
类的前两个方法不返回任何内容。作为解决方法,我在第三种方法中采用了硬编码方法,这对于生产代码来说当然是不可持续的。
理想的解决方案将具有以下签名:
public static ReadOnlyCollection<PropertyInfo> GetApplicationDbContextDbSets ()
{
var properties = typeof(ApplicationDbContext)
.GetProperties();
return (properties.AsReadOnly());
}
我一定是遗漏了什么或者错误地使用了 API。
如有任何建议,我们将不胜感激。
此过滤应该满足您的要求:
public static ReadOnlyCollection<PropertyInfo> GetApplicationDbContextDbSets()
{
var properties = typeof(ApplicationDbContext)
// Properties must be instance, public, and virtual.
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.GetGetMethod()?.IsVirtual == true)
// Properties must inherit from DbSet<IEntity<TEntity>>
.Where(x => x.PropertyType.IsGenericType)
.Where(x => x.PropertyType.GetGenericTypeDefinition().IsAssignableFrom(typeof(DbSet<>)))
.Where(x => x.PropertyType.GetGenericArguments().Length == 1)
// The generic Dbset properties must have exactly one generic parameter IEntity<TEntity>
.Where(x => x.PropertyType.GetGenericArguments()[0]
.GetInterfaces()
.Where(y => y.IsGenericType)
.Where(y => y.GetGenericTypeDefinition().IsAssignableFrom(typeof(IEntity<>)))
// The generic parameter IEntity<TEntity> must have exactly one nested generic parameter TEntity.
.Where(y => y.GetGenericArguments().Length == 1)
// TEntity must adhere to the generic type constraints enforced by IEntity<TEntity>
.Where(y => y.GetGenericArguments()[0].IsAssignableFrom(x.PropertyType.GetGenericArguments()[0])).Any()
)
.ToList();
return (properties.AsReadOnly());
}
在生产代码中,我会将其写为每个循环的完整代码,而不是 LINQ,以获得更好的可调试性和更少的重复表达式。