mardi 28 septembre 2021

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

I have taken a leaf out of EFC and tried to develop something similar to modelBuilder.ApplyConfigurationsFromAssembly() for SQL commands that I need to run against my database in a specific order.

I would like to invoke all the methods of any class where that class inherits from my Interface. But I want to invoke them in groups or orders.

My interface is:

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

An example nested class is:

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 
        ");
    }
}

So using System.Reflection I am able to find the interface and invoke the interface by using:

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;
            }
        }
    }
}

So that all works fine, and all the instances get invoked, but what I now want to do is

  1. find all the classes that have that Interface; and
  2. invoke Configure() by the order of ExecutionGroup

The definition of ExecutionGroups is:

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

I can't work out the Linq to order my classes by the value of ExecutionGroup so that my Sql executes in order of dependency.





Aucun commentaire:

Enregistrer un commentaire