C # Лямбда-выражения или делегаты как свойства или аргументы - PullRequest
7 голосов
/ 27 сентября 2008

Я хочу создать класс ValidationRule, который проверяет свойства объекта типа объекта. Мне бы очень хотелось задать имя проверяемого свойства, а затем дать классу делегат или лямбда-выражение, которое будет оцениваться во время выполнения, когда объект запускает свой метод IsValid (). У кого-нибудь есть фрагмент чего-то подобного или какие-либо идеи о том, как передать анонимный метод в качестве аргумента или свойства?

Кроме того, я не уверен, объясняю ли я то, что пытаюсь сделать, поэтому, пожалуйста, задавайте вопросы, если мне не ясно.

Ответы [ 5 ]

6 голосов
/ 27 сентября 2008

Действительно, вы хотите использовать Func<T,bool>, где T - тип элемента, который вы хотите проверить Тогда вы бы сделали что-то вроде этого

validator.AddValidation(item => (item.HasEnoughInformation() || item.IsEmpty());

Вы можете хранить их в List<Func<T,bool>>.

3 голосов
/ 27 сентября 2008
class ValidationRule {
    public delegate bool Validator();

    private Validator _v;

    public ValidationRule(Validator v) { _v = v; }

    public Validator Validator {
        get { return _v; }
        set { _v = value; }
    }

    public bool IsValid { get { return _v(); } }
}

var alwaysPasses = new ValidationRule(() => true);
var alwaysFails = new ValidationRule(() => false);

var textBoxHasText = new ValidationRule(() => textBox1.Text.Length > 0);

Это должно начать вас. Но на самом деле наследование здесь гораздо более уместно. Проблема просто в том, что Validator не имеет доступа ни к одному состоянию, которое он не закрывает, это означает, что он не так многократно используется, как, скажем, ValidationRules, который содержит свое собственное состояние. Сравните следующий класс с предыдущим определением textBoxHasText.

interface IValidationRule {
    bool IsValid { get; }
}

class BoxHasText : IValidationRule {
    TextBox _c;

    public BoxHasText(TextBox c) { _c = c; }

    public bool IsValid {
        get { return _c.Text.Length > 0; }
    }
}
2 голосов
/ 27 сентября 2008

Ну, просто, если у вас есть класс Entity, и вы хотите использовать лямбда-выражения в этом Entity, чтобы определить, является ли что-то допустимым (возвращая логическое значение), вы можете использовать Func.

Итак, учитывая сущность:

 class Entity
 {
      public string MyProperty { get; set; }
 }

Вы можете определить класс ValidationRule для этого следующим образом:

 class ValidationRule<T> where T : Entity
 {
      private Func<T, bool> _rule;

      public ValidationRule(Func<T, bool> rule)
      {
           _rule = rule;
      }

      public bool IsValid(T entity)
      {
           return _rule(entity);
      }
 }

Тогда вы можете использовать это так:

 var myEntity = new Entity() { MyProperty = "Hello World" };
 var rule = new ValidationRule<Entity>(entity => entity.MyProperty == "Hello World");

 var valid = rule.IsValid(myEntity);

Конечно, это только одно из возможных решений.

Если вы удалите вышеуказанное общее ограничение («где T: Entity»), вы можете сделать это универсальным механизмом правил, который можно использовать с любым POCO. Вам не нужно будет создавать класс для каждого типа использования, который вам нужен. Поэтому, если бы я хотел использовать этот же класс в TextBox, я мог бы использовать следующее (после удаления общего ограничения):

 var rule = new ValidationRule<TextBox>(tb => tb.Text.Length > 0);
 rule.IsValid(myTextBox);

Это довольно гибкий способ. Совместное использование лямбда-выражений и обобщений очень эффективно. Вместо того, чтобы принимать Func или Action, вы можете принять Expression> или Expression> и иметь прямой доступ к дереву Express, чтобы автоматически исследовать такие вещи, как имя метода или свойства, тип выражения и т. Д. И люди, использующие ваш класс не должен был бы изменить одну строку кода.

1 голос
/ 27 сентября 2008

что-то вроде:

class ValidationRule
{
    private Func<bool> validation;

    public ValidationRule(Func<bool> validation)
    {
        this.validation = validation;
    }
    public bool IsValid()
    {
        return validation();
    }
}

будет больше в стиле C # 3, но компилируется в тот же код, что и ответ @Frank Krueger. Это то, что вы просили, но не чувствует себя хорошо. Есть ли веская причина, по которой сущность не может быть расширена для выполнения проверки?

0 голосов
/ 12 февраля 2009

Будет ли работать такой синтаксис определения правила, как этот?

  public static void Valid(Address address, IScope scope)
  {
    scope.Validate(() => address.Street1, StringIs.Limited(10, 256));
    scope.Validate(() => address.Street2, StringIs.Limited(256));
    scope.Validate(() => address.Country, Is.NotDefault);
    scope.Validate(() => address.Zip, StringIs.Limited(10));

    switch (address.Country)
    {
      case Country.USA:
        scope.Validate(() => address.Zip, StringIs.Limited(5, 10));
        break;
      case Country.France:
        break;
      case Country.Russia:
        scope.Validate(() => address.Zip, StringIs.Limited(6, 6));
        break;
      default:
        scope.Validate(() => address.Zip, StringIs.Limited(1, 64));
        break;
    }

Проверьте Проверка DDD и правила на основе правил в .NET для получения дополнительной информации

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...