1

I have a generic class that one of its fields is a generic service. In this class, I have a method with the name InitialQueue that its purpose is to call one of the generic service methods that I give it to InitialQueue method. My problem is that I do not have any idea how to invoke the method.

public class RabbitConsumer<I, E> : IHostedService
    where I : class
    where E : class
{
    private readonly I service;

    public RabbitConsumer(I service)
    {
        this.service = service;
    }

    public RabbitConsumer(Expression<Func<I, Func<E, object>>> method, IConfiguration config, string entryQueueName) : base()
    {
        InitialQue(method);
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        Dispose();
        return Task.CompletedTask;
    }

    private void InitialQue(Expression<Func<I, Func<E, object>>> method)
    {
        //For example this is the object that I get through RabbitMq
        var myObject = JsonConvert.DeserializeObject<E>(new { Id = 1, Name = "My Category"});
    
        //I need something like that but I don't have any idea what to do
        service.Invoke(method(myObject));
    }
}
  • you need to set a constraint for the generic parameter `I` like described in the [documentation](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint) all your services need to implement a certain interface which you can use for the constrain. Then intellisense will show you the available methods and you can call them – Mong Zhu Jun 10 '21 at 14:15
  • 1
    Any reason not to make 'method' a `Func` and simply call it like `method(service, myObject)` ? what is the purpose of the expressions etc? – JonasH Jun 10 '21 at 14:38
  • @JonasH Thank you, it works. I wish your comment was an answer and I could accept it. – Farshad Shahsavari Jun 11 '21 at 14:26

2 Answers2

1

There are two typical approaches when dealing with generic objects.

One is to use a delegate to indirectly access any property or method of the object. I.e. replace Expression<Func<I, Func<E, object>>> with Func<I, E, object>. That way you could call it with method(service, myObject). This would usually be my preferred method.

Another option is to use generic constraints. I.e. create a interface

public interface IMyInterface<T>{
    public object MyMethod(T obj);
}

and add a restriction for your class, ... where I : class, IMyInterface<E>. This should let you call the method, service.MyMethod(myObject)

JonasH
  • 28,608
  • 2
  • 10
  • 23
0

As mentioned by Mong Zhu, if you qualify more of your incoming generics such as

  where I : class

you can tack on other other things as well, such as new() if the object type allows for "new" to create a new instance, or other interfaces that can expose the method(s) you are trying to get access to. Simple change like

  where I : class, new(), ICanDoThisInterface, ICanDoThatInterface

So now, wherever you have the "I" generic such as stored in your "service" field, you could do

var tmp = new I();
tmp.MethodFromTheICanDoThisInterface();
tmp.MethodFromTheICanToThatInterface();
DRapp
  • 47,638
  • 12
  • 72
  • 142