工厂创建泛型类

时间:2012-03-09 10:31:42

标签: c# generics factory-pattern fluentvalidation

我有一个名为Validator的抽象类:

public abstract class Validator<T> where T : IValidatable
{
    public abstract bool Validate(T input);
}

我有一些具体的实现。一个是AccountValidator:

public class AccountCreateValidator : Validator<IAccount>
{
    public override bool Validate(IAccount input)
    {
        //some validation
    }
}

另一个是LoginValidator:

public class LoginValidator : Validator<IAccount>
{
    public override bool Validate(IAccount input)
    {
        //some different validation
    }
}

我现在想创建一个工厂来返回验证器实现的实例。类似的东西:

public static class ValidatorFactory
{
    public static Validator GetValidator(ValidationType validationType)
    {
        switch (validationType)
        {
            case ValidationType.AccountCreate:
                return new AccountCreateValidator();
        }
    }
}

然后我想把它称为

Validator myValidator = ValidatorFactory.GetValidator(ValidationType.AccountCreate); 

但是它不喜欢返回新的AccountCreateValidator()行,或者我将myValidator声明为Validator而不是Validator<SomeType>。 任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

您似乎正在使用工厂将枚举参数转换为具体的验证实现。但我想,虽然调用者不知道或不关心验证器的具体类型,但它可能知道它希望它验证的类型。这应该意味着使GetValidator方法成为通用方法是合理的:

public static Validator<TypeToValidate> GetValidator<TypeToValidate>(ValidationType validationType) where TypeToValidate : IValidatable

然后调用代码看起来像这样: Validator<IAccount> validator = ValidatorFactory.GetValidator<IAccount>(ValidationType.AccountCreate

答案 1 :(得分:1)

如果你想像你所说的那样使用它,而不指定泛型参数那么你可以声明一个非泛型接口并使你成为Validator抽象类的实现。未经测试,但这些方面的内容:

public interface IValidator 
{
    bool Validate(object input);
}

public abstract class Validator<T> : IValidator where T : IValidatable
{
    public abstract bool Validate(T input);

    public bool Validate (object input)
    {
        return Validate ((T) input);
    }
}

public static class ValidatorFactory
{
    public static IValidator GetValidator(ValidationType validationType)
    {
        switch (validationType)
        {
            case ValidationType.AccountCreate:
                return new AccountCreateValidator();
        }
    }
}

然后这段代码:

IValidator myValidator = ValidatorFactory.GetValidator(ValidationType.AccountCreate); 

应该可以正常工作。

答案 2 :(得分:0)

通常我会有一个工厂接受Type作为参数,以便工厂创建一个唯一的派生类型。但是因为你有多个验证器接受相同类型的对象来验证(在这种情况下是一个IAccount)我认为你必须为你的工厂提供通用参数以及要创建什么样的验证器,像这样:

public static class ValidatorFactory
{
    public static Validator<T> GetValidator<T>(ValidationType validationType) 
        where T : IValidatable
    {
        switch (validationType)
        {
            case ValidationType.AccountCreate:
                return new AccountCreateValidator() as Validator<T>;
                    // etc...
        }
    }
}

我试过打电话:

var value = ValidatorFactory.GetValidator<IAccount>(ValidationType.AccountCreate)

现在这会将AccountCreateValidator广告投放回正确的Validator<IAccount>类型。

它并不完全理想,因为您现在需要知道您想要的验证器以及它接受的输入,但是如果由于我添加的显式强制转换而传递错误的输入类型,您应该希望得到编译错误,例如: ValidatorFactory.GetValidator<IUser>(ValidationType.AccountCreate)应该失败。

编辑,因为评论说这不会编译,我已经编辑了上面的代码片段来执行转换为new AccountCreateValidator() as Validator<T>。我认为它可以是任何一种方式,但显然不是(不确定为什么)。我已在LINQPad中验证了这一点,我可以从验证器返回结果。

我也相信我之前关于可能会收到编译错误的评论如果你传入错误的泛型类型不再代表使用as关键字进行投射只会返回null如果它无法做到它