2009-02-21 2 views
0

Итак, у меня есть простой шаблон правила проверки, который я использую для проверки на объектах сущности. Вот мой ValidationRule класс:У меня проблемы с дженериками и литье в C#

public class ValidationRule { 

    public Func<object, bool> Rule { get; set; } 
    public string ErrorMessage { get; set; } 

    public ValidationRule(string errorMessage, Func<object, bool> rule) { 
     Rule = rule; 
     ErrorMessage = errorMessage; 
    } 

    public bool IsValid(object obj) { 
     return Rule(obj); 
    } 
} 

У меня есть базовый класс для своих объектов сущностей, которые инкапсулируют методы для выполнения проверки, которая выглядит следующим образом:

public abstract class ModelBase { 

    private List<ValidationRule> _validationRules; 
    public List<ValidationRule> ValidationRules { 
     get { 
      if (_validationRules == null) 
       _validationRules = new List<ValidationRule>(); 
      return _validationRules; 
     } 
     set { _validationRules = value; } 
    } 

    public ValidationResult Validate() { 
     var result = new ValidationResult(); 
     rules.ForEach(r => { 
      if (!r.IsValid(this)) 
       result.Errors.Add(
        new ValidationError(r.ErrorMessage, r.PropertyName));    
      }); 
     return result; 
    } 
} 

А теперь вот реальная проблема я пытаясь решить. Когда я создаю новый класс, который наследует от ModelBase, добавление правил проверки немного неудобно. Например:

public class Client : ModelBase { 

    public int ID{ get; set; } 
    public string Name { get; set; } 
    public Address MailingAddress { get; set; } 

    public Client() { 
     CreateValidationRules(); 
    } 

    private void CreateValidationRules() { 

     ValidationRules.Add(new ValidationRule("Client 'Name' is required.", 
      c => !string.IsNullOrEmpty(((Client)c).Name))); 
    } 
} 

Обратите внимание, где я создаю список правил проверки. Внутри лямбда-выражения мне нужно отбросить «c» на «Клиент», потому что мое правило - это, по существу, Func<object, bool>. Я пробовал много способов сделать это generic, делая что-то вроде ValidationRule<Client>, но у меня всегда возникают проблемы с вызовом Validate() в классе ModelBase. Любые идеи о том, как обойти это литье?

+0

в качестве примечания, Func <объекта, BOOL> такой же, как Predicate bendewey

+0

„То же“типа функциональности. Но по какой-то странной причине они не совпадают в системе типов. – MichaelGG

+0

Они не то же самое, но вы можете конвертировать между ними. –

ответ

4

Вы можете сделать класс ValidationRule общим, но оставить параметр для метода IsValid в качестве объекта и выполнить литье в методе. Таким образом, вы получаете дженериков, не создавая также generic ModelBase.

Вам также нужен интерфейс для ModelBase, чтобы иметь возможность сохранять список правил проверки, не зная их фактического типа. Затем просто измените тип списка и свойство в ModelBase на IValidationRule.

. (Примечание: Вы можете использовать частный сеттер на свойства, чтобы сделать их только для чтения)

public Interface IValidationRule { 
    bool IsValid(object); 
} 

public class ValidationRule<T> : IValidationRule { 

    public Func<T, bool> Rule { get; private set; } 
    public string ErrorMessage { get; private set; } 

    public ValidationRule(string errorMessage, Func<object, bool> rule) { 
     Rule = rule; 
     ErrorMessage = errorMessage; 
    } 

    public bool IsValid(object obj) { 
     return Rule((T)obj); 
    } 
} 

Теперь, тип параметра в выражении лямбда является универсальным типом, поэтому вы надеваете «т придется бросить его:

ValidationRules.Add(
     new ValidationRule<Client>(
      "Client 'Name' is required.", 
      c => !string.IsNullOrEmpty(c.Name) 
    ) 
); 
1

Я подозреваю, что ModelBase также должен стать универсальным. Мне непонятно, что здесь происходит, - не являются ли правила валидации одинаковыми для каждый Клиент? Правила проверки правильны, они должны быть связаны с целым типом, а не с отдельными экземплярами типа. Они были бы подтвержденным против одного экземпляра, правда.

Интересно, не следует ли иметь тип Validator<T> и создать (один раз) код Validator<Client>, который затем может быть проверен в отношении любого экземпляра Client.

+0

Is Predicate предпочитает Func <объект, bool>? – bendewey

+0

Лично я думаю, что это яснее, да. Я не уверен, почему LINQ использует Func для таких вещей, как Where. –

+0

Предикат для одной перегрузки и Func для другого ... nah. http://msdn.microsoft.com/en-us/library/system.linq.enumerable.where.aspx –

Смежные вопросы