使用反射查找 Type() 的所有 类,对它们进行排序,并调用命名方法

Using reflection to find all Classes of a Type(), ordering them, and invoking a named method

我借鉴了 EFC 并尝试为 SQL 命令开发类似于 modelBuilder.ApplyConfigurationsFromAssembly() 的东西,我需要以特定顺序对我的数据库 运行。

我想调用任何 class 的所有方法,其中 class 继承自我的 Interface。但我想按组或顺序调用它们。

我的界面是:

public interface IDatabaseSqlCommands
{
    public ExecutionGroups ExecutionGroup { get; }
    public Task Configure(DbContext context);
}

一个嵌套的例子 class 是:

private sealed class SqlCommands : IDatabaseSqlCommands
{
    public ExecutionGroups ExecutionGroup { get; } = ExecutionGroups.G1;

    public async Task Configure(DbContext ctx)
    {
        await ctx.Database.ExecuteSqlRawAsync(
        @"
            CREATE TRIGGER Customers_Timestamp
            AFTER UPDATE ON Customers
            BEGIN
                UPDATE Customers
                SET Version = Version + 1
                WHERE rowid = NEW.rowid;
            END 
        ");
    }
}

所以使用 System.Reflection 我能够找到接口并使用以下方法调用接口:

public async Task EnsureSqlCreatedAsync()
{
    // We are only interested in non-abstact private nested classes which are sealed
    var classCollection = Assembly.GetExecutingAssembly()
                            .DefinedTypes.Where(
                                t => !t.IsAbstract &&
                                t.IsClass &&
                                t.IsSealed &&
                                t.IsNestedPrivate);

    foreach (var type in classCollection)
    {
        // Class must have an empty constructor
        if (type.GetConstructor(Type.EmptyTypes) == null)
            continue; // Constructor is not empty

        foreach (var @interface in type.GetInterfaces())
        {
            if (@interface.GetTypeInfo() == typeof(IDatabaseSqlCommands))
            {
                var instance = Activator.CreateInstance(type);
                await ((IDatabaseSqlCommands)instance).Configure(this);
                return;
            }
        }
    }
}

所以一切正常,所有实例都被调用,但我现在想做的是

  1. 找到所有具有该接口的 class;和
  2. 按ExecutionGroup
  3. 的顺序调用Configure()

ExecutionGroups的定义是:

public enum ExecutionGroups
{
    G1=1, G2=2, G3=3, G4=4, G5=6
}

我无法计算出 Linq 按 ExecutionGroup 的值对我的 classes 进行排序,以便我的 Sql 按依赖顺序执行。

您可以像这样将循环转换为 LINQ 查询(并在那里进行排序):

var commands = classCollection
    .Where(type => 
        type.GetConstructor(Type.EmptyTypes) != null &&
        type.GetInterfaces().Any(i => i.GetTypeInfo() == typeof(IDatabaseSqlCommands)))
    .Select(type => (IDatabaseSqlCommands) Activator.CreateInstance(type))
    .OrderBy(c => c.ExecutionGroup);
foreach (var command in commands) {
    await command.Configure(this);
}