泛型接口的运行时强制转换

本文关键字:转换 运行时 泛型接口 | 更新日期: 2023-09-27 18:01:58

我有一个命令处理例程,它需要从我的IOC容器中获取一个Processor对象并在其上调用ProcessCommand,处理器是实现通用接口的具体对象:

public interface ICommandProcessor<in T> where T : Command
{        
    Error ProcessCommand(T command);
}

我遇到的问题是,当我试图检索处理器时,我只有通过基类(command)对命令对象的引用,所以我不知道T的类型(运行时除外)

我已经引入了第二个非泛型接口

public interface ICommandProcessorGeneric
{
}
public interface ICommandProcessor<in T>:ICommandProcessorGeneric where T : Command
{        
    Error ProcessCommand(T command);
}

,可以从IOC容器中检索处理器,如下所示:

 protected virtual CommandProcessingResult RecognizeAndProcessCommand<T>(T command) where T : Command
 {
    ICommandProcessor<T> commandProcessor;
    try
    {
        Debug.WriteLine(String.Format( "---- Looking for processor for type {0}", command.GetType().Name));
        var g = ServiceLocator.GetInstance<ICommandProcessorGeneric>(command.GetType().Name);                
        commandProcessor = g as ICommandProcessor<T>;  //returns null!!
        Debug.WriteLine(String.Format("---- Got Processor {0}", g.GetType().Name));
    }
    catch (Exception ex)
    {
        //handle the exception
    }
    return commandProcessor.ProcessCommand(command);
}

问题是commandProcessor是空的T是命令,而在运行时,我知道T是派生类型。从IOC容器返回的对象g是正确的过程,但是我不知道如何将g转换为允许我访问ProcessCommand方法的类型。

我还应该指出,对该方法的调用无法在编译时确定命令的类型,因为命令仅通过引用ID字段并反序列化从数据库中检索。

泛型接口的运行时强制转换

我已经写了一篇关于这个问题的博文。

所以基本上我在过去所做的就是为你的命令处理器创建一个抽象基类以及一个通用类:

public abstract class CommandProcessor
{
    public abstract Error ProcessCommand(Command command);
}
public abstract class CommandProcessor<TCommand> where TCommand : Command
{
    public override Error ProcessCommand(Command command)
    {
        if (command is TCommand == false)
            throw new ArgumentException("command should be of type TCommand");
        var cast = (TCommand)command;
        return this.ProcessCommand(cast);
    }
    public abstract Error ProcessCommand(TCommand command);
}

现在你不需要做任何特殊的依赖于什么类型的命令你正在使用:

protected virtual CommandProcessingResult RecogniseAndProccessCommand<T>
    (T command) where T : Command
{
    var commandProcessor = (CommandProcessor)ServiceLocator.GetInstance<ICommandProcessorGeneric>(typeof(T).Name);
    return commandProcessor.ProcessCommand(command);
}