C#Lambda表达式或者委托作为属性或者参数
我正在寻找创建一个ValidationRule类来验证实体类型对象上的属性。我真的很想设置要检查的属性的名称,然后为该类提供一个委托或者一个lambda表达式,当对象运行其IsValid()方法时将在运行时对其进行评估。是否有人像这样的代码片段,或者关于如何将匿名方法作为参数或者属性传递的任何想法?
另外,我不确定是否要解释要完成的工作,因此如果不清楚,请提出问题。
解决方案
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; } } }
确实,我们要使用的是Func <T,bool>
,其中T是我们要验证的项目的类型。然后你会做这样的事情
validator.AddValidation(item => (item.HasEnoughInformation() || item.IsEmpty());
我们可以将它们存储在List <Func <T,bool >>
中。
就像是:
class ValidationRule { private Func<bool> validation; public ValidationRule(Func<bool> validation) { this.validation = validation; } public bool IsValid() { return validation(); } }
将会是更多的C3样式,但将其编译为与@Frank Krueger的答案相同的代码。
这是我们要的,但是感觉不对。有充分的理由为什么不能扩展实体来执行验证吗?
好吧,简单来说,如果我们有一个Entity类,并且想在该Entity上使用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);
当然,那只是一种可能的解决方案。
如果删除上面的通用约束(" T是实体"),则可以使它成为可与任何POCO一起使用的通用规则引擎。我们不必为所需的每种使用类型派生一个类。因此,如果我想在TextBox上使用相同的类,则可以使用以下内容(删除通用约束之后):
var rule = new ValidationRule<TextBox>(tb => tb.Text.Length > 0); rule.IsValid(myTextBox);
这样非常灵活。一起使用lambda表达式和泛型非常强大。除了接受Func或者Action,我们还可以接受Expression>或者Expression>并直接访问快速树以自动调查诸如方法或者属性的名称,其类型是什么类型的表达式等。使用人类不必更改一行代码。
这样的规则定义语法对我们有用吗?
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; }
在.NET中签出DDD和规则驱动的UI验证以了解更多信息