Pull up Generic Type to interface

I have an IModule interface defined as below:

    public interface IModule
    {
        //Properties
        string StoreName { get; set; }
    
        void Execute();

        T ApiClient; // <-- How do I do this?
    }
    

I also have an abstract class defined as:

    public abstract class ModuleBase<T> : IModule where T : IAPIClient
    {
        public T ApiClient { get; private set; }

        public abstract Task Execute();
    }

I then inherit ModuleBase in a class such as:

    public class DemoModule : ModuleBase<DemoApiClient>
    {
        public override string StoreName => "Demo"

        public override async Task Execute(){
           ApiClient.DoStuff();
           //... some long running stuff here
        } 
    }

DemoApiClient is defined as:

public class DemoApiClient : IAPIClient
{
    public IProxyManger ProxyManager {get; set;}
    public IHttpClient  HttpClient   {get; set;}
    
    public void DoStuff() {
       Console.Log("DemoApiClient - DoStuff");
    }
}

IAPIClient is an interface with the following declarations:

    public interface IAPIClient
    {
        IProxyManager ProxyManager { get; }

        IHTTPClient HttpClient { get; }
    }

How can I pull up the generic ApiClient on ModuleBase up to IModule? I want to ensure that every implementation of IModule can implement the implementation of IAPIClient?

The reason I need this is because of the following example:

IModule module = (IModule)Activator.CreateInstance(typeof(DemoModule));
module.ApiClient.DoStuff()

Note that DoStuff() is specific to DemoApiClient and other implementations of IAPIClient will contain methods specific to them. For this reason, I cannot pull up DoStuff() to IAPIClient.


Solution 1:

You need to make IModule generic

public interface IModule<T> where T : IApiClient
{    
    Task Execute();

    T ApiClient {get;}
}

Then:

public abstract class ModuleBase<T> : IModule<T> where T : IAPIClient
{
    public T ApiClient { get; private set; }

    public abstract Task Execute();
}

You'll need to know the type:

DemoModule module = (DemoModule)Activator.CreateInstance(typeof(DemoModule));
module.ApiClient.DoStuff()

But lets take a step back here; why do you think IModule needs to know about the APIClient at all, when you never use it outside of the base class?

You original code should work just fine as you only call ApiClient.DoStuff(); from Execute