按特定标准过滤类属性

问题描述 投票:0回答:1

考虑以下模型(.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。

如有任何建议,我们将不胜感激。

c# .net reflection
1个回答
0
投票

此过滤应该满足您的要求:

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,以获得更好的可调试性和更少的重复表达式。

© www.soinside.com 2019 - 2024. All rights reserved.