Error instantiate a Generic class

I'm create C# windows application and using FluentValidation for validating a View Model. In every form I always create validation method like this:

private bool ValidateCustomer(CustomerViewModel customerVM)
{
    CustomerValidator validator = new CustomerValidator();
    ValidationResult results = validator.Validate(customerVM);

    if (!results.IsValid)
    {
        StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

        foreach (var failure in results.Errors)
        {
            errorMessage.AppendLine("- " + failure.ErrorMessage);
        }

        MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        return false;
    }

    return true;
}

public class CustomerValidator : AbstractValidator<CustomerViewModel>
{
    public CustomerValidator()
    {
        RuleFor(c => c.Code).NotEmpty();
        RuleFor(c => c.Name).NotEmpty();
    }
}

I want to create Generic ValidationHelper class so that I don't write the same validation code (just different validator and viewmodel class) in every form, for example: ValidationHelper<MyValidator, MyViewModel>.Validate(). I'm just replace MyValidator and MyViewModel class for the other form. When make this Generic class I'm having problem when instantiate a validator class.

public static class ValidatorHelper<T, V> 
        where T : class, new() 
        where V : class, new()
    {
        public static bool Validate(T t, V n)
        {
            T validator = new T(); 
            ValidationResult results = validator.Validate(n); // <--- error on this line

            if (!results.IsValid)
            {
                StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

                foreach (var failure in results.Errors)
                {
                    errorMessage.AppendLine("- " + failure.ErrorMessage);
                }

                MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return false;
            }

            return true;
        }
    }

How to solve this problem?

UPDATE:

As @JonSkeet and @dbc suggestion, I modified the ValidatorHelper to:

public static class ValidatorHelper<T, V>
    where T : AbstractValidator<V>, new()
    where V : class, new()
{
    public static bool Validate(V v)
    {
        T validator = new T();
        ValidationResult results = validator.Validate(v);

        if (!results.IsValid)
        {
            StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

            foreach (var failure in results.Errors)
            {
                errorMessage.AppendLine("- " + failure.ErrorMessage);
                //log.Message("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
            }

            MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        return true;
    }
}

I'm not using T on public static bool Validate(V v) because it will be instantiated in it. Then on the form, you've just write:

if (ValidatorHelper<CustomerValidator, CustomerViewModel>.Validate(customerVM))

Thanks to you both, I can solve the problem, I really appreciate it.

Jon Skeet
people
quotationmark

You're trying to assign a CustomerValidator reference to a variable of type T. What if T is StringBuilder or something like that?

Fundamentally, it seems odd for your ValidationHelper to claim to be generic, but then be specific to CustomerValidator.

Without knowing about the FluentValidation library, we can't really know what CustomerValidator does - does it implement Validator<Customer> for example? It strikes me that you might want to pass the validator into the Validate method, or into the ValidatorHelper constructor. (I strongly suspect that you want to get rid of both of the static modifiers - if the method is static, it can't be implementing an abstract method in the base class... and if the class is static, it can't even specific a base class.)

Fundamentally, you need to consider:

  • What should know about CustomerValidator? Probably not a generic helper class.
  • What should create the validator? Options:
    • The helper itself (making use of the new() constraint, potentially)
    • The caller who creates an instance of the helper, assuming you're going to have an instance
    • Whatever calls your Validate method

You may want something like this:

// No constraint on V - why would you need one?
public class ValidatorHelper<T, V> : AbstractValidator<V> 
        where T : AbstractValidator<V>
{
    public bool Validate(T validator, V value)
    {
        ValidationResult results = validator.Validate(value);

        if (!results.IsValid)
        {
            StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");

            foreach (var failure in results.Errors)
            {
                errorMessage.AppendLine("- " + failure.ErrorMessage);
            }

            MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }

        return true;
    }
}

people

See more on this question at Stackoverflow