简体   繁体   English

工厂创建泛型类

[英]Factory to create generic classes

I have an abstract class called Validator: 我有一个名为Validator的抽象类:

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

And I have a few concrete implementations. 我有一些具体的实现。 One is AccountValidator: 一个是AccountValidator:

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

Another would be LoginValidator: 另一个是LoginValidator:

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

I now want to create a factory to return the an instance of a validator implementation. 我现在想要创建一个工厂来返回验证器实现的实例。 Something like: 就像是:

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

I'd then like to do call it like 然后我喜欢这样称呼它

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

However it doesn't like the return new AccountCreateValidator() line, or the fact I'm declaring myValidator as Validator and not Validator<SomeType> . 但是它不喜欢返回新的AccountCreateValidator()行,或者我将myValidator声明为Validator而不是Validator<SomeType> Any help would be appreciated. 任何帮助,将不胜感激。

It seems that you are using the factory to translate an enum argument into a concrete validation implementation. 您似乎正在使用工厂将枚举参数转换为具体的验证实现。 But I would imagine that although the caller does not know or care about the concrete type of the validator, it presumably does know the type it wishes it to validate. 但我想,虽然调用者不知道或不关心验证器的具体类型,但它可能知道它希望它验证的类型。 That should mean that it is reasonable to make the GetValidator method a generic method: 这应该意味着使GetValidator方法成为通用方法是合理的:

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

Then calling code would look like this: Validator<IAccount> validator = ValidatorFactory.GetValidator<IAccount>(ValidationType.AccountCreate ) 然后调用代码如下所示: Validator<IAccount> validator = ValidatorFactory.GetValidator<IAccount>(ValidationType.AccountCreate

if you want it to be used like you have said, without specifying the generic parameter then you can declare a non generic interface and make you Validator abstract class implement that. 如果你想像你所说的那样使用它,而不指定泛型参数那么你就可以声明一个非泛型接口并使你成为Validator抽象类的实现者。 Untested but something along these lines: 未经测试但是沿着这些方向:

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();
        }
    }
}

then this code: 然后这段代码:

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

Should work ok. 应该工作正常。

Normally I would have a factory which accepted a Type as a parameter so that the factory would create a unique derived type. 通常情况下,我会有一个工厂接受一个Type作为参数,以便工厂创建一个唯一的派生类型。 But because you have multiple validators that accept the same kind of object to validate (in this case an IAccount ) I think you'll have to provide the generic parameter to your factory as well as what kind of validator to create, like this: 但是因为你有多个验证器接受相同类型的对象来验证(在这种情况下是一个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...
        }
    }
}

I've tried calling: 我试着打电话:

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

and this now returns an AccountCreateValidator cast to the correct Validator<IAccount> type. 现在返回一个AccountCreateValidator Validator<IAccount>转换为正确的Validator<IAccount>类型。

It's not exactly ideal as you now need to know what validator you want and what input it accepts, but you should hopefully get a compilation error if passing the wrong input type because of the explicit cast I've added, eg ValidatorFactory.GetValidator<IUser>(ValidationType.AccountCreate) should fail. 它并不完全理想,因为您现在需要知道您想要的验证器以及它接受的输入,但是如果由于我添加的显式ValidatorFactory.GetValidator<IUser>(ValidationType.AccountCreate)传递了错误的输入类型,您应该希望得到编译错误,例如ValidatorFactory.GetValidator<IUser>(ValidationType.AccountCreate)应该失败。

EDIT: because of the comment saying this would not compile, I've edited the above code snippet to do the cast as new AccountCreateValidator() as Validator<T> . 编辑:因为评论说这不会编译,我编辑了上面的代码片段作为new AccountCreateValidator() as Validator<T>进行演员。 I thought it could be cast either way, but apparently not (not sure why though). 我认为它可以是任何一种方式,但显然不是(不确定为什么)。 I have verified this works in LINQPad and I can get a result back from a validator. 我已经在LINQPad中验证了这个功能,我可以从验证器获得结果。

I also believe my previous comment about possibly getting a compilation error if you pass in the wrong generic types no longer stands as casting using the as keyword would just return null if it was unable to do it. 我也相信我之前关于可能会出现编译错误的评论,如果传入错误的泛型类型不再表示使用as关键字进行投射,如果无法执行,则返回null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM