Search code examples
c#reflectionactivator

Activator.CreateInstance and passing a boxed object to an invoked method


I have the following code ...

My Command handler:

public class MyHandler : IHandler
{
  // I Want to get rid of this method
  public override void ExecuteOperation(BaseOperation operation)
  {
    // This is a work-around
    this.ExecuteOperation(operation as SpecificOperation);
  }

  public override void ExecuteOperation(SpecificOperation operation)
  {
    // Do actual work here
  }
}

My Command handler dispatcher:

private dynamic FindOperationHandler(TBaseProvisioningOperation operation)
{
  ... some logic here
  return Activator.CreateInstance(handlerType, ... args here ...)
}

My consumer code

public void PerformProvisioningOperation(BaseOperation operation)
{
  // Find the correct handler for this operation
  var operationHandler = this.FindOperationHandler(operation as TBaseProvisioningOperation);

  // make it execute the operation
  // NOTE: 'operation' is SpecificOperation type, for example
  operationHandler.ExecuteOperation(operation); // <--- problem is here
}

The issue is that when I create an instance of my handler class with the Activator.CreateInstance and pass it a boxed object (i.e. as "BaseOperation") parameter, .NET looks for a method in the handler, which has a parameter of the base type, instead of automatically invoking the one which can handle the object if it were unboxed (i.e. explicitly cast).

Of course we have SpecificOperation : BaseOperation

In other words: I want when I execute operationHandler.ExecuteOperation(operation);, .NET to invoke ExecuteOperation(SpecificOperation operation) instead of ExecuteOperation(BaseOperation operation), because the operation parameter is boxed (i.e. it IS SpecificOperation but is downcast-ed as BaseOperation).

How do I achieve that?

Edit:

public interface IHandler<TOperation> where TOperation : BaseOperation
    {
        /// <summary>
        /// TODO: Get rid of this method
        /// </summary>
        /// <param name="operation">The operation to execute - boxed</param>
        void ExecuteOperation(BaseOperation operation);

        /// <summary>
        /// Executes the operation
        /// </summary>
        /// <param name="operation">The operation to execute - unboxed</param>
        void ExecuteOperation(TOperation operation);
    }

Solution

  • Assuming you're using dynamic here to achieve Double-Dispatch, the problem is that you're casting the wrong object.

    It's the operation variable that needs to be casted (in order to defer overload resolution until runtime), not the operationHandler.

    Try this instead:

    operationHandler.ExecuteOperation(operation as dynamic);
    

    And you can avoid the redundant dynamic definition on your FindOperationHandler:

    private IHandler FindOperationHandler(TBaseProvisioningOperation operation)
    {
      return Activator.CreateInstance(handlerType, ... args here ...) as IHandler;
    }
    

    See Double-Dispatch