Как вызвать метод generi c с параметром Action <T>, используя отражение в C# - PullRequest
0 голосов
/ 01 мая 2020

Я хочу, чтобы этот код назывался generi c.

services.AddDbContext<ProductsDbContext>(options =>
{
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
        sqlServerOptions =>
        {
            sqlServerOptions.MigrationsAssembly("Modules.Products");
        });
});

Это из entityframeworkcore. См. Документацию здесь .

Я создал класс для получения компоновщика:

public static class DbContextExtensions
{
    public static Action<DbContextOptionsBuilder> GetDbContextOptionsBuilder(string connectionString, AssemblyName moduleName)
    {
        return options =>
        {
            options.UseSqlServer(connectionString,
                sqlServerOptions =>
                {
                    sqlServerOptions.MigrationsAssembly(moduleName.Name);
                });
        };
    }
}

И я создал следующее для вызова метода:

var moduleAssembly = Assembly.GetAssembly(manifest);
var moduleName = moduleAssembly.GetName();

// Get dbcontext like ProductsDbContext
var dbContext = moduleAssembly.GetTypes().Where(p => typeof(DbContext).IsAssignableFrom(p)).First();

// Get the correct extensionmethod with Action<DbContextOptionsBuilder>
MethodInfo addDbContextMethod = typeof(EntityFrameworkServiceCollectionExtensions)
    .GetMethod(nameof(EntityFrameworkServiceCollectionExtensions.AddDbContext),
        1,
        new Type[] { typeof(ServiceCollection), typeof(Action<DbContextOptionsBuilder>), typeof(ServiceLifetime), typeof(ServiceLifetime) });
MethodInfo generic = addDbContextMethod.MakeGenericMethod(dbContext);


// But how to pass the Action<DbContextOptionsBuilder> method?
// I tried the following but i'm lost...
var delegateType = typeof(Action<>).MakeGenericType(typeof(DbContextOptionsBuilder));
var methodInfo = typeof(DbContextExtensions).GetMethod(nameof(DbContextExtensions.GetDbContextOptionsBuilder));
var del = Delegate.CreateDelegate(delegateType, null, methodInfo);

// invoke subscribe method
generic.Invoke(services, new[] { del });

Есть идеи? Спасибо

1 Ответ

0 голосов
/ 01 мая 2020

Из вашего кода я вижу, что DbContextExtensions - это ваш локальный класс, который вам не нужно вызывать с помощью Reflection, поэтому вы можете вызвать метод GetDbContextOptionsBuilder напрямую, предоставив правильные параметры и получить действие. Затем вы можете вызвать метод generic с сгенерированными действиями.

        var moduleAssembly = Assembly.GetAssembly(manifest);            
        var moduleName = moduleAssembly.GetName();
        var dbContext = moduleAssembly.GetTypes().Where(p => typeof(DbContext).IsAssignableFrom(p)).First();


        MethodInfo addDbContextMethod = typeof(EntityFrameworkServiceCollectionExtensions)
            .GetMethod(nameof(EntityFrameworkServiceCollectionExtensions.AddDbContext),
                1,
                new Type[] { typeof(IServiceCollection), typeof(Action<DbContextOptionsBuilder>), typeof(ServiceLifetime), typeof(ServiceLifetime) });

        MethodInfo generic = addDbContextMethod.MakeGenericMethod(dbContext);

        var action = DbContextExtensions.GetDbContextOptionsBuilder("connectionString", moduleName);

        generic.Invoke(null, new object[] { services, action, ServiceLifetime.Scoped, ServiceLifetime.Scoped });

Если вы хотите получить действие из внешней сборки, вы можете использовать тот же подход, динамически получая информацию о методе GetDbContextOptionsBuilder и вызывая его с параметрами, и в результате вы получаете действие, которое можно использовать при вызове метода generic.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...