c# - 使用 Activator.CreateInstance 后转换为正确的类型

标签 c# interface casting activator createinstance

在使用仅返回对象类型的 Activator.CreateInstance(...) 后,我在转换为正确类型时遇到问题。所以我的代码如下。 我有一个空接口(interface)来将对象定义为命令..

/// <summary>
/// Defines the expected members for a Command object
/// </summary>
public interface ICommand { }

我有一个实现该接口(interface)的命令

/// <summary>
/// Contains command data for adding a company
/// </summary>
public class CompanyAddCommand : ICommand
{
    #region Properties

    public bool IsActive { get; protected set; }
    public string CompanyName { get; protected set; }
    public DateTime RecordCreatedDateTime { get; protected set; }

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="CompanyAddCommand"/> class.
    /// </summary>
    /// <param name="isActive">if set to <c>true</c> [is active].</param>
    /// <param name="companyName">Name of the company.</param>
    /// <param name="recordCreatedDateTime">The record created date time.</param>
    public CompanyAddCommand(bool isActive,
        string companyName, DateTime recordCreatedDateTime)
    {
        IsActive = isActive;
        CompanyName = companyName;
        RecordCreatedDateTime = recordCreatedDateTime;
    }

    #endregion
}

我有一个命令验证器接口(interface),它有一个方法 Validate() 和一个类型参数,它是一个必须是类并实现 ICommand 接口(interface)的对象。

public interface IValidationHandler<in TCommand> 
    where TCommand : class, ICommand
{
    /// <summary>
    /// Validates the specified command.
    /// </summary>
    /// <param name="command">The command.</param>
    void Validate(TCommand command);
}

我有一个实现 IValidationHandler 的命令验证器类

public class CompanyAddValidator : ValidatorBase, IValidationHandler<CompanyAddCommand>
{
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="CompanyAddValidator"/> class.
    /// </summary>
    public CompanyAddValidator(IUnitOfWork unitOfWork)
        : base(unitOfWork)
    { }

    #endregion

    #region IValidationHandler<CompanyAddCommand> Members

    /// <summary>
    /// Validates the specified command.
    /// </summary>
    /// <param name="command">The command.</param>
    public void Validate(
        CompanyAddCommand command)
    {
        ValidateCompanyEntity(command);
        ValidationUniqueCompanyName(command);
    }

    #endregion

    /// <summary>
    /// Validates the company entity.
    /// </summary>
    /// <param name="command">The command.</param>
    private void ValidateCompanyEntity(CompanyAddCommand command)
    {
        // do some work            
    }

    /// <summary>
    /// Validations the name of the unique company.
    /// </summary>
    /// <param name="command">The command.</param>
    private void ValidationUniqueCompanyName(CompanyAddCommand command)
    {
        // do some work;
    }
}

我有一个命令总线,它在构造时扫描程序集以查找所有处理程序类型的类,并将这些类型注册为两个字典之一中的命令处理程序或验证处理程序,其中键是命令类型,值是处理程序类型。

public class CommandBus : ICommandBus
{
    #region Fields

    private Dictionary<Type, Type> _commandHandlerTypes;
    private Dictionary<Type, Type> _validationHandlerTypes;

    private readonly IUnitOfWork _unitOfWork;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="CommandBus"/> class.
    /// </summary>
    public CommandBus(IUnitOfWork unitOfWork)
    {
        // Validate arguments
        if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");

        // Cache the UOW
        _unitOfWork = unitOfWork;

        RegisterAllHandlerTypes();
    }

    #endregion

    #region ICommandBus Members

    /// <summary>
    /// Submits the specified command.
    /// </summary>
    /// <typeparam name="TCommand">The type of the command.</typeparam>
    /// <param name="command">The command.</param>
    /// <returns></returns>
    public ICommandResult Submit<TCommand>(TCommand command) 
        where TCommand : class, ICommand
    {
        Validate(command);
        return SubmitInternal(command);
    }

    #endregion

    #region Methods : private

    /// <summary>
    /// Gets the command handler types.
    /// </summary>
    /// <returns></returns>
    private static Dictionary<Type, Type> GetCommandHandlerTypesFromAssembly()
    {
        // Create a function that will return true if the type is of type ICommandHandler
        Func<Type, bool> isCommandHandler = t => t.GetInterfaces()
           .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>));

        // Use this function to register the command handlers in this assembly
        Assembly assembly = Assembly.GetCallingAssembly();
        return GetSpecificHandlerTypesFromAssembly(assembly, isCommandHandler);
    }

    /// <summary>
    /// Registers all of the handler types.
    /// </summary>
    private void RegisterAllHandlerTypes()
    {
        _commandHandlerTypes = GetCommandHandlerTypesFromAssembly();
        _validationHandlerTypes = GetValidationHandlerTypesFromAssembly();
    }

    /// <summary>
    /// Gets the specific handler types using the specified function to determine correct types.
    /// </summary>
    /// <param name="assembly">The assembly to get hansdlers from</param>
    /// <param name="isCorrectTypeCallback">A function that returns true if the Type is correct.</param>
    /// <returns></returns>
    private static Dictionary<Type, Type> GetSpecificHandlerTypesFromAssembly(
        Assembly assembly, 
        Func<Type, bool> isCorrectTypeCallback)
    {
        Func<Type, IEnumerable<Tuple<Type, Type>>> collect = t => t.GetInterfaces()
            .Select(i => Tuple.Create(i.GetGenericArguments()[0], t));

        return assembly
            .GetTypes()
            .Where(t => !t.IsAbstract && !t.IsGenericType)
            .Where(isCorrectTypeCallback)
            .SelectMany(collect)
            .ToDictionary(x => x.Item1, x => x.Item2);
    }

    /// <summary>
    /// Gets the validation handlers.
    /// </summary>
    /// <returns></returns>
    private static Dictionary<Type, Type> GetValidationHandlerTypesFromAssembly()
    {
        // Create a function that will return true if the type is of type IValidationHandler
        Func<Type, bool> isValidationHandler = t => t.GetInterfaces()
           .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidationHandler<>));

        // Use this function to register the validation handlers in this assembly
        Assembly assembly = Assembly.GetCallingAssembly();
        return GetSpecificHandlerTypesFromAssembly(assembly, isValidationHandler);
    }

    private ICommandResult SubmitInternal(object command)
    {
        // do some work
    }

    private void Validate<TCommand>(TCommand command)
        where TCommand : class, ICommand
    {
        // Get the command type and check if we have a validator for that type
        Type commandType = command.GetType();
        bool hasValidator = _validationHandlerTypes.ContainsKey(commandType);

        // If we don't have a validator dont worry, just break leve the method
        if (!hasValidator) return;

        // Create and instance of the handler
        Type validatorType = _validationHandlerTypes[commandType];
        var handler = Activator.CreateInstance(validatorType, _unitOfWork);
        Type handlerType = handler.GetType();
        var handlerB = handler as IValidationHandler<TCommand>;
        var handlerC = handler as IValidationHandler<ICommand>;

        //handler.Validate(command); compiler fails as handler is OBJECT

        if (handlerB != null) handlerB.Validate(command);
        if (handlerC != null) handlerC.Validate(command);
    }    

    #endregion
}

我遇到的问题是在 Validate() 方法中,虽然我可以创建我的命令验证器的实例并且它显示(悬停在变量上)它是正确的类型(即 CompanyAddValidator 的实例)我无法调用Validate() 方法,因为它是一个对象。如果我尝试将此处理程序转换为 IValidationHandler < TCommand > 或 IValidationHandler < ICommand >(即 handlerB 和 handlerC),以便我可以在接口(interface)上调用“Validate()”方法,我会得到一个空引用。

我无法获得允许我需要的通用级别的正确语法,并且无法在实例化的 CompanyAddValidator 对象或我可能拥有的任何其他域实体验证器上调用 Validate() 方法。

有人能给我指出正确的方向吗?我尝试按照这些示例进行操作,但没有成功。

http://stackoverflow.xluat.com/questions/30739865/command-bus-dispatcher-and-handler-registration-without-dependency-injection

Can I use Activator.CreateInstance with an Interface?

https://alertcoding.wordpress.com/2013/03/18/command-and-query-based-entity-framework-architecture-part-2/comment-page-1/#comment-153

最佳答案

你可以这样做:

dynamic handler = Activator.CreateInstance(validatorType, _unitOfWork);
handler.Validate((dynamic)command);

或者你可以这样做:

handler.GetType().GetMethod("Validate").Invoke(handler,new object[] {command});

注意:如果你之前没有读过,我建议你阅读如何写Minimal, Complete, and Verifiable example .您给出的代码不一致,例如,您试图调用不带参数的 handler.Validate,而该方法是用一个参数定义的,您的 Submit CommandBus 类上的方法不返回任何内容,而它的签名需要 ICommandResult 等等的结果类型等等。这使得回答您的问题变得更加困难。

关于c# - 使用 Activator.CreateInstance 后转换为正确的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31470337/

相关文章:

c# - 在 .NET Core 的 ConfigureService-Methods(特别是 IApplicationLifetime)中使用 DI

python - 使用 Python 作为界面时的奇怪控件

c++ - QByteArray 转换和指针转换

json - 转换 JSON 对象以从中提取数据时出错

c++ - Ada 到 C++ : Pass an unsigned 64-bit value

java - org.firebirdsql.jdbc.FBBlob 到文件

c# - 将列表存储在所有用户都可以访问的内存中

C# 阻塞等待响应

c# - 括号中带有(属性)的方法参数

arrays - 来自数组类型的 Typescript 接口(interface)