简体   繁体   English

如何使用 Action 调用泛型方法<t>在 C# 中使用反射的参数</t>

[英]How to invoke generic method with Action<T> parameter using reflection in C#

I want this code to be called generic.我希望将此代码称为通用代码。

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

It's from entityframeworkcore.它来自实体框架核心。 See the documentation here .请参阅此处的文档

I created a class for getting the builder:我创建了一个 class 来获取构建器:

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

And I created the following for invoke the method:我为调用该方法创建了以下内容:

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

Any ideas?有任何想法吗? Thanks谢谢

From your code I see that DbContextExtensions is your local class which you don't need to call using Reflection, so you can call the GetDbContextOptionsBuilder method directly providing the correct parameters and get the action.从您的代码中,我看到DbContextExtensions是您不需要使用反射调用的本地 class ,因此您可以直接调用GetDbContextOptionsBuilder方法,提供正确的参数并获取操作。 Then you can call your generic method with the generated actions.然后您可以使用生成的操作调用您的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 });

If you want to get the action from the external assembly, you can use the same approach by dynamically getting the GetDbContextOptionsBuilder method info and calling it with parameters and as the result you get the action which you can use in calling your generic method.如果您想从外部程序集中获取操作,您可以通过动态获取GetDbContextOptionsBuilder方法信息并使用参数调用它来使用相同的方法,结果您将获得可用于调用generic方法的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM