7

我正在寻找一个 ValidationRule 类来验证实体类型对象的属性。我真的很想设置要检查的属性的名称,然后给类一个委托或 lambda 表达式,当对象运行其 IsValid() 方法时,它将在运行时进行评估。有没有人有这样的片段,或者关于如何将匿名方法作为参数或属性传递的任何想法?

另外,我不确定我是否在解释我要完成的工作,所以如果我不清楚,请提出问题。

4

5 回答 5

6

实际上,您要使用的是Func<T,bool>其中 T 是您要验证的项目的类型。然后你会做这样的事情

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

您可以将它们存储在List<Func<T,bool>>.

于 2008-09-26T21:35:39.960 回答
3
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; }
    }
}
于 2008-09-26T21:32:20.687 回答
2

好吧,简单地说,如果你有一个实体类,并且你想在那个实体上使用 lambda 表达式来确定某些东西是否有效(返回布尔值),你可以使用 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);

当然,这只是一种可能的解决方案。

如果您删除上面的通用约束(“where T : Entity”),您可以使其成为可与任何 POCO 一起使用的通用规则引擎。您不必为所需的每种使用类型派生一个类。因此,如果我想在 TextBox 上使用同一个类,我可以使用以下内容(在删除通用约束之后):

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

这种方式非常灵活。结合使用 lambda 表达式和泛型是非常强大的。除了接受 Func 或 Action,您还可以接受 Expression> 或 Expression> 并直接访问 express 树以自动调查方法或属性的名称、它是什么类型的表达式等。类不必更改一行代码。

于 2008-09-26T21:42:52.890 回答
1

就像是:

class ValidationRule
{
    private Func<bool> validation;

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

将是更多的 C# 3 风格,但编译为与@Frank Krueger 的答案相同的代码。这是你要求的,但感觉不对。实体不能扩展以执行验证有充分的理由吗?

于 2008-09-26T21:41:17.700 回答
0

Would a rule definition syntax like this one work for you?

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

Check out DDD and Rule driven UI Validation in .NET for more information

于 2009-02-12T14:28:46.427 回答