【问题标题】:Activator.CreateInstance and passing a boxed object to an invoked methodActivator.CreateInstance 并将装箱对象传递给调用的方法
【发布时间】:2016-05-26 15:47:52
【问题描述】:

我有以下代码...

我的命令处理程序:

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
  }
}

我的命令处理程序调度程序:

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

我的消费者代码

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
}

问题是,当我使用 Activator.CreateInstance 创建处理程序类的实例并将其传递一个装箱对象(即作为“BaseOperation”)参数时,.NET 会在处理程序中查找一个方法,该方法具有一个基本类型的参数,而不是自动调用可以处理对象的参数,如果它被取消装箱(即显式转换)。

我们当然有SpecificOperation : BaseOperation

换句话说:我希望当我执行operationHandler.ExecuteOperation(operation); 时,.NET 调用ExecuteOperation(SpecificOperation operation) 而不是ExecuteOperation(BaseOperation operation),因为操作参数被装箱(即它是SpecificOperation,但被向下转换为@987654331 @)。

我如何做到这一点?

编辑:

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);
    }

【问题讨论】:

  • 如果完整的代码在 C# 中,您应该避免返回 dynamic
  • FindOperationHandler 返回的实际类型是什么?另外,TBaseProvisioningOperation 是什么?是否涉及任何泛型?
  • @JeroenvanLangen,我假设这里使用dynamic 来实现双重调度
  • 我试图摆脱动态,但没有成功。会再试一次。是的,涉及到泛型,但是它们只与我的命令查找逻辑(有效)相关,所以我试图将它们排除在这个问题之外。 “动态”背后的实际类型是(类似于)IHandler,带有一些泛型参数化。
  • 只需使用base 参数类型,并在实现中进行类型转换。

标签: c# reflection activator


【解决方案1】:

假设你在这里使用dynamic 来实现Double-Dispatch,问题是你投错了对象。

需要强制转换的是 operation 变量(为了将重载决议推迟到运行时),而不是 operationHandler

试试这个:

operationHandler.ExecuteOperation(operation as dynamic);

您可以避免在您的FindOperationHandler 上使用多余的dynamic 定义:

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

Double-Dispatch

【讨论】:

  • 你是神。谢谢,参数中的as dynamic 解决了我的问题!
【解决方案2】:

如果完整的代码在 C# 中,则应避免返回 dynamicActivator.CreateInstance 正在返回 Object 而不是动态的。 当属性/方法不是强类型时,动态用于脚本语言之间的互操作。

很遗憾你没有描述IHandler 接口,但是...

我认为;你面临的问题是你的接口定义了你的类必须实现void ExecuteOperation(BaseOperation operation); 这样你的FindOperationHandler 应该返回一个IHandler

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

对于您的处理程序:

public class MyHandler : IHandler
{

    public override void ExecuteOperation(BaseOperation operation)
    {
        var operation = (SpecificOperation)operation;
        // Do actual work here
    }
}

【讨论】:

  • 我已经编辑了我的问题以包含处理程序接口的定义。另外,感谢您的回答,但我的目标是不必投射。我想使用 IHandler 接口中通过泛型实现的强类型方法参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2011-09-27
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多