Как сделать валидацию родовой - PullRequest
0 голосов
/ 27 февраля 2012

У меня есть следующий код C #.Здесь валидации хранятся вне класса для соответствия принципу Open - Closed.Это работает нормально.Но проблема в том, что валидации не являются общими.Это специфично для класса сотрудников (например, DateOfBirthRuleForEmployee).Как сделать проверки универсальными для всех объектов (DateOfBirthRuleForAnyObject).

Примечание: сделать общий <==> сделать независимым от типа

Примечание: у меня также есть проверка NameLengthRuleForEmployee.Новая проверка может произойти в будущем.

РЕДАКТИРОВАТЬ

Пример общего метода: Использование «OfType» в LINQ

CODE

    class Program
    {
    static void Main(string[] args)
    {
        Employee employee = new Employee();
        employee.DateOfBirth = DateTime.Now;
        employee.Name = "Lijo";
        DateOfBirthRuleForEmployee dobRule = new
        DateOfBirthRuleForEmployee();
        NameLengthRuleForEmployee nameRule = new
        NameLengthRuleForEmployee();
        EmployeeManager employeeManager = new EmployeeManager();
        employeeManager.AddRules(dobRule);
        employeeManager.AddRules(nameRule);
        bool result = employeeManager.validateEntity(employee);
        Console.WriteLine(result);
        Console.ReadLine();
    }
}
public interface IEntity
{
}
public interface IRule<TEntity>
{
    bool IsValid(TEntity entity);
}
public class DateOfBirthRuleForEmployee : IRule<Employee>
{
    public bool IsValid(Employee entity)
    {
        return (entity.DateOfBirth.Year <= 1975);
    }
}
public class NameLengthRuleForEmployee : IRule<Employee>
{
    public bool IsValid(Employee employee)
    {
        return (employee.Name.Length < 5);
    }
}
public class Employee : IEntity
{
    private DateTime dateOfBirth;
    private string name;
    public DateTime DateOfBirth
    {
        get
        {
            return dateOfBirth;
        }
        set
        {
            dateOfBirth = value;
        }
    }
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}
public class EmployeeManager
{
    RulesEngine<Employee> engine = new RulesEngine<Employee>();
    public void AddRules(IRule<Employee> rule)
    {
        engine.AddRules(rule);
        //engine.AddRules(new NameLengthRuleForEmployee());
    }
    public bool validateEntity(Employee employee)
    {
        List<IRule<Employee>> rulesList = engine.GetRulesList();
        //No need for type checking. Overcame Invariance problem
        bool status = true;
        foreach (IRule<Employee> theRule in rulesList)
        {
            if (!theRule.IsValid(employee))
            {
                status = false;
                break;
            }
        }
        return status;
    }
}
public class RulesEngine<TEntity> where TEntity : IEntity
{
    private List<IRule<TEntity>> ruleList = new
    List<IRule<TEntity>>();
    public void AddRules(IRule<TEntity> rule)
    {
        //invariance is the key term
        ruleList.Add(rule);
    }
    public List<IRule<TEntity>> GetRulesList()
    {
        return ruleList;
    }
}

1 Ответ

4 голосов
/ 27 февраля 2012

Задача состоит в том, чтобы ваши правила знали, какое свойство какого типа проверять. Вы можете обеспечить это либо путем реализации интерфейса, который предоставляет именно это, как предложено SLaks, либо путем динамического отказа от него, либо предоставив конкретному классу правил немного больше информации о том, как получить доступ к данному свойству, например ::

.
class NameRule<T> : IRule<T>  
{
    private Func<T, string> _nameAccessor;

    public NameRule(Func<T, string> nameAccessor)
    {
        _nameAccessor = nameAccessor;
    }

    public bool IsValid(T instance)
    {
        return _nameAccessor(instance).Length > 10;
    }
}

этот курс можно использовать следующим образом:

NameRule<Employee> employeeNameRule = new NameRule<Employee>(x => x.name);
employeeManager.addRule(employeeNameRule);
...