1

Lets say I have:

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

I am used to execute it on Hangfire scheduler:

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

Now I would like to replace concrete type ConcreteJob with its string representation "ConcreteJob". Use reflection and do something like this (very simple said):

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

I am getting lost in all the reflection...

Lambda as parameter makes this different from other threads on stack overflow.

What I have so far:

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) });
5
  • It would be better if we knew why you wanted this functionality? Surely you could just get the string name of the type with nameof(ConcreteJob) further down the line in processing? Again this is a complete guess without knowing why you actually want this functionality, I look forward to discussing :) Commented Aug 7, 2020 at 10:25
  • You have stated perfectly what you want, so far so good, but show no attempt whatsoever at solving it, you only state "getting lost". Please show the code you have, the error that yields and what you have tried to solve it. You can't call ExecuteConcreteJob() on a type that you don't know at compile-time, you want to create that expression using strings as well? Therefore I closed as duplicate with the most basic instructions to start solving that. If you have a more specific problem, edit your question to show that problem. Commented Aug 7, 2020 at 10:28
  • "You can't call ExecuteConcreteJob() on a type that you don't know at compile-time, you want to create that expression using strings as well" This is exactly the point. I will update the question with code I have now. Commented Aug 7, 2020 at 10:30
  • Why would you use reflection instead of interfaces? Interfaces with polymorphism is much cleaner and faster than refrelction. Commented Aug 7, 2020 at 10:46
  • 1
    Using interfaces I am still facing the same problem. I have to point interface with its method. Or am I wrong? Commented Aug 7, 2020 at 11:22

1 Answer 1

1

Lambda as parameter makes this different from other threads on stack overflow.

The ExecuteCleanup method accepts a delegate as a parameter, not a lambda expression. Hence, you need to compile your lambda expression to a delegate before passing it as a parameter.

Note that this is not a cheap operation. It makes sense to cache compiled delegates somewhere and re-use them.

Since your lambda expression accepts a parameter, you need to declare this parameter and pass it to the 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() });
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.