在使用仅返回对象类型的Activator.CreateInstance(...)后,我遇到了转换为正确类型的问题。所以我的代码如下。 我有一个空接口来将对象定义为命令..
/// <summary>
/// Defines the expected members for a Command object
/// </summary>
public interface ICommand { }
我有一个实现该接口的命令
/// <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
}
我有一个命令验证器接口,它有一个单独的方法Validate(),并且有一个类型参数,它是一个必须是类的对象,并实现ICommand接口。
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;
}
}
我有一个命令总线,在构造中扫描程序集以查找处理程序类型的所有类,并将这些类型注册为两个dictionarys之一中的命令处理程序或验证处理程序,其中键是命令类型,值是处理程序类型。
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&lt; TCommand&gt;或IValidationHandler&lt; ICommand&gt; (即handlerB和handlerC)所以我可以调用&#34; Validate()&#34;接口上的方法我得到一个空引用。
我无法获得允许我需要的泛型级别的正确语法,并且能够在实例化的CompanyAddValidator对象或我可能拥有的任何其他域实体验证器上调用Validate()方法。
任何人都可以指出我正确的方向吗?我试着按照这些例子,但没有运气。
答案 0 :(得分:2)
你可以这样做:
dynamic handler = Activator.CreateInstance(validatorType, _unitOfWork);
handler.Validate((dynamic)command);
或者你可以这样做:
handler.GetType().GetMethod("Validate").Invoke(handler,new object[] {command});
注意:如果您之前没有阅读过,我建议您阅读如何撰写Minimal, Complete, and Verifiable example。您提供的代码是quire不一致的,例如,您尝试在没有参数的情况下调用handler.Validate
,其中方法是使用一个参数定义的,Submit
方法在{ {1}}类不返回任何内容,而它的签名需要CommandBus
et cetra,et cetra的结果类型。这使得回答你的问题变得更加困难。