我是Generics实施的新手,需要对我面临的两个问题提出意见:
我有一个接口ICommand定义为:
public ICommand
{
List<T> Execute<T>() where T : IValidationResult;
IDomain<T> GetDO<T>() where T : IValidationResult;
}
故意我把它作为非泛型的,因为我必须添加一组不同的命令。
这个接口我希望在一个名为PersistCommand的泛型类中实现为:
public PersistCommand<TDomainObj,T> : ICommand where TDomainObj : IDomain<T> where T : IValidationResult
{
private TDomainObj _domainObject;//IDomain<T> is an interface
public PersistCommand(TDomainObj TDomainObject)
{
_domainObject = TDomainObject;
}
public IDomain<T> GetDO<T>() where T : IValidationResult
{
return _domainObject as IDomain<T>;
}
public List<T> Execute<T>() where T : IValidationResult
{
//returns a list<T>
}
}
拥有泛型类的目的是将这些约束从类传递给这些泛型方法,遗憾的是不会发生这种情况(不确定为什么?编译时,我收到警告:类型参数'T'具有相同的名称作为外部类型'PersistCommand'的类型参数这是第一个问题。
第二个问题是: 我有不同的命令集,InsertCommand,DeleteCommand和UpdateCommand继承自PersistCommand,并且在单独调用Execute()方法时工作正常。
我有一个CommandManager类,用于执行多个命令,如下所示:
public class CommandManager
{
public virtual IEnumerable<T> Perform<T>(List<ICommand> commandList)
where T : IValidationResult
{
List<T> validationResults = new List<T>();
//fire pre-intent validations
foreach (ICommand command in commandList)
{
validationResults.AddRange(command.GetDomainObject<T>().Validate(command.GetPreIntent()) );
}
//fire intent validations
if (validationResults.Count == 0)
{
foreach (ICommand command in commandList)
{
validationResults.AddRange(command.Execute<T>());
}
}
//fire post-intent validations
if (validationResults.Count == 0)
{
foreach (ICommand command in commandList)
{
validationResults.AddRange(command.GetDomainObject<T>().Validate(command.GetPostIntent()));
}
}
return validationResults;
}
}
只要传递给Commands的类型“T”和CommandManager.Perform方法相同,它就可以工作。 但我有一个场景,其中我们有两个具有不同“T”类型的域对象:
class Project : IDomain<CustomResult>//CustomResult implements IValidationResult
class Resource : IDomain<AnotherResult>//AnotherResult implements IValidationResult
当我调用CommandManager.Perform(commandList)时,它会在
处抛出异常GetDO方法显示消息:对象引用未设置为对象的实例“
任何有助于解决此问题的帮助或想法都将受到赞赏。
答案 0 :(得分:2)
第一个问题源于您在方法定义中声明泛型类型T
而不是整体接口定义。
因此要进行编译,您必须将接口和类定义更改为:
public interface ICommand<T> where T : IValidationResult
{
List<T> Execute();
IDomain<T> GetDO();
}
public class PersistCommand<TDomainObj,T> : ICommand<T> where TDomainObj : IDomain<T> where T : IValidationResult<T>
{
private TDomainObj _domainObject;//IDomain<T> is an interface
public PersistCommand(TDomainObj TDomainObject)
{
_domainObject = TDomainObject;
}
public IDomain<T> GetDO()
{
return _domainObject as IDomain<T>;
}
public List<T> Execute()
{
//returns a list<T>
}
}
您还可以将实现类中的方法声明为使用名称不是T的泛型类型,但这只会增加更多的复杂性。
然而,我认为这一切都被更广泛的问题所黯然失色 - 你似乎试图使用像接口这样的泛型。
从提供的代码示例来看,您看起来并不一定需要像使用泛型一样使用泛型,而且只会使问题复杂化
我会尝试简化它:
public interface ICommand
{
List<IValidationResult> Execute();
IDomain<IValidationResult> GetDO();
}
public class PersistCommand<TDomainObj> : ICommand where TDomainObj : IDomain<IValidationResult>
{
private TDomainObj _domainObject;//
public PersistCommand(TDomainObj TDomainObject)
{
_domainObject = TDomainObject;
}
public IDomain<IValidationResult> GetDO()
{
return _domainObject;
}
public List<IValidationResult> Execute()
{
//returns a list<T>
}
}
public class CommandManager
{
public virtual IEnumerable<IValidationResult> Perform(List<ICommand> commandList)
{
List<IValidationResult> validationResults = new List<IValidationResult>();
//fire pre-intent validations
foreach (ICommand command in commandList)
{
validationResults.AddRange(command.GetDO().Validate(command.GetPreIntent()) );
}
//fire intent validations
if (validationResults.Count == 0)
{
foreach (ICommand command in commandList)
{
validationResults.AddRange(command.Execute());
}
}
//fire post-intent validations
if (validationResults.Count == 0)
{
foreach (ICommand command in commandList)
{
validationResults.AddRange(command.GetDO().Validate(command.GetPostIntent()));
}
}
return validationResults;
}
}
这样你就可以对待所有相同的东西(即通过界面),这就是你想要做的事情。您使用泛型的唯一方法是在PersistCommand中指定域对象的特定类型,我认为您可能需要内部使用或子类。