【问题标题】:C# Call generic method with type as string with lambda argumentC# 使用 lambda 参数调用类型为字符串的泛型方法
【发布时间】:2020-08-07 10:10:05
【问题描述】:

假设我有:

public class ConcreteJob
{
    public void ExecuteConcreteJob(string someParam) { }
}

我习惯在 Hangfire 调度器上执行它:

var client = new BackgroundJobClient();
client.Enqueue<ConcreteJob>(job => job.ExecuteConcreteJob("test_string_param"));

现在我想用它的字符串表示 "ConcreteJob" 替换具体类型 ConcreteJob。使用反射,做这样的事情(很简单的说):

client.Enqueue<"ConcreteJob">(job => job.ExecuteConcreteJob("test_string_param"));

我迷失在所有的反思中......

Lambda 作为参数使得这与堆栈溢出的其他线程不同。

到目前为止我所拥有的:

var jobType = Type.GetType("ConcreteJob");
MethodInfo methodInfo = typeof(BackgroundJobClient).GetMethod("Enqueue").MakeGenericMethod(jobType);
var funcDelegateType = typeof(Func<>).MakeGenericType(jobType);
dynamic lambda = Expression.Lambda(funcDelegateType,
        Expression.Call(
            Expression.Parameter(jobType, "job"),
            jobType.GetMethod("ExecuteCleanup"),
            Expression.Constant(UserPrincipalName))
    );
methodInfo.Invoke(client, new[] { (Action)(lambda) });

【问题讨论】:

  • 如果我们知道您为什么想要这个功能会更好?当然,您可以在处理过程中进一步获取带有 nameof(ConcreteJob) 类型的字符串名称?再次,这是一个完整的猜测,不知道你为什么真正想要这个功能,我期待讨论:)
  • 你已经完美地表达了你想要的,到目前为止一切都很好,但没有表现出任何解决它的尝试,你只是说“迷路了”。请显示您拥有的代码、产生的错误以及您尝试解决的问题。您不能在编译时不知道的类型上调用ExecuteConcreteJob(),您还想使用字符串创建该表达式吗?因此,我以最基本的说明关闭了副本以开始解决该问题。如果您有更具体的问题,请edit 您的问题以表明该问题。
  • “您不能在编译时不知道的类型上调用 ExecuteConcreteJob(),您还想使用字符串创建该表达式”这正是重点。我将使用我现在拥有的代码更新问题。
  • 为什么要使用反射而不是接口?具有多态性的接口比反射更干净、更快速。
  • 使用接口我仍然面临同样的问题。我必须用它的方法来指向接口。还是我错了?

标签: c# .net reflection


【解决方案1】:

Lambda 作为参数使得这与堆栈溢出的其他线程不同。

ExecuteCleanup 方法接受委托作为参数,而不是 lambda 表达式。因此,您需要先将 lambda 表达式编译为委托,然后再将其作为参数传递。

请注意,这不是一个便宜的操作。在某处缓存已编译的委托并重新使用它们是有意义的。

由于您的 lambda 表达式接受参数,因此您需要声明此参数并将其传递给 Expression.LambdaMethod。

MethodInfo methodInfo = typeof(BackgroundJobClient).GetMethod("Enqueue").MakeGenericMethod(jobType);
var funcDelegateType = typeof(Action<>).MakeGenericType(jobType);
ParameterExpression parameter = Expression.Parameter(jobType, "job");
LambdaExpression lambda = Expression.Lambda(funcDelegateType,
        Expression.Call(
            parameter,
            jobType.GetMethod("ExecuteCleanup"),
            Expression.Constant(UserPrincipalName)),
        parameter
    );
methodInfo.Invoke(client, new[] { lambda.Compile() });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多