Search code examples
c#genericsreflectioninterfaceazure-service-fabric

Interface from string to use as generic type


I'm using Service Fabric in Azure and set up a proxy to an actor like this:

var proxy = ActorProxy.Create<T>(actorId);

Where T must be specified as the interface of the actor I'm calling.

Let's say I have the name of the interface as a string:

var interfaceName = "IUserActor";

Is there a way to instatiate a generic type by this string name? And if there is, how do I call a method specified in given interface by it's string name?

All actor interfaces inherits from IActor which is a part of Service Fabric.

Now I understand that this is not recommended, the point is to be able to access the actor state for a given actor, from tests and administrative purposes. Speed is insignificant in this case, so any reflection approach will do.

So, a basic usage example, not using the dynamic interface name:

public async Task<string> AdminGetState(ActorId actorId, string interfaceName){
   var proxy = ActorProxy.Create<IUserActor>(actorId);
   var state = await proxy.AdminGetStateJson();
   return JsonConvert.SerializeObject(state);
}

Solution

  • It's not pretty or efficient, but you can do this using reflection...

    public async Task<string> AdminGetState(ActorId actorId, string interfaceName){
    
       //Find the type information for "interfaceName".  (Assuming it's in the executing assembly)
       var interfaceType = Assembly.GetExecutingAssembly().GetType(interfaceName);
    
       //Use reflection to get the Create<> method, and generify it with this type
       var createMethod = typeof(ActorProxy).GetMethod(nameof(ActorProxy.Create)).MakeGenericMethod(interfaceType);
    
       //Invoke the dynamically reflected method, passing null as the first argument because it's static
       object proxy = createMethod.Invoke(null,new object[] { actorId });
    
       //As per your comments, find the "AdminGetStateJson" method here.  You're REALLY trusting that it exists at this point.
       var adminGetStateMethod = interfaceType.GetMethod("AdminGetStateJson");
    
       Task<string> stateTask = (Task<string>)adminGetStateMethod.Invoke(proxy, null);
    
       var state = await stateTask;
       return JsonConvert.SerializeObject(state);
    }
    

    Final edit: Is this definitely what you want to be doing though? I would be very hesitant to put code like this out in the wild.