C# Lambda 表达式或委托作为属性或参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/142090/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# Lambda Expressions or Delegates as a Properties or Arguments
提问by JC Grubbs
I'm looking to create an ValidationRule class that validates properties on an entity type object. I'd really like to set the name of the property to inspect, and then give the class a delegate or a lambda expression that will be evaluated at runtime when the object runs its IsValid() method. Does anyone have a snippet of something like this, or any ideas on how to pass an anonymous method as an argument or property?
我希望创建一个 ValidationRule 类来验证实体类型对象上的属性。我真的很想设置要检查的属性的名称,然后为类提供一个委托或一个 lambda 表达式,当对象运行其 IsValid() 方法时,将在运行时评估该表达式。有没有人有这样的片段,或者关于如何将匿名方法作为参数或属性传递的任何想法?
Also, I'm not sure if I'm explaining what I'm trying to accomplish so please ask questions if I'm not being clear.
另外,我不确定我是否在解释我要完成的任务,所以如果我不清楚,请提出问题。
回答by Frank Krueger
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);
That should get you started. But, really, inheritance is far more appropriate here. The problem is simply that the Validator
doesn't have access to any state that it doesn't close over, this means that it isn't as reusable as say ValidationRules
that contain their own state. Compare the following class to the previous definition of textBoxHasText
.
这应该让你开始。但是,实际上,继承在这里更合适。问题很简单,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; }
}
}
回答by Darren Kopp
Really, what you want to use is Func<T,bool>
where T is the type of the item you want to validate. Then you would do something like this
实际上,您要使用的是Func<T,bool>
其中 T 是您要验证的项目的类型。然后你会做这样的事情
validator.AddValidation(item => (item.HasEnoughInformation() || item.IsEmpty());
you could store them in a List<Func<T,bool>>
.
您可以将它们存储在List<Func<T,bool>>
.
回答by Hamish Smith
something like:
就像是:
class ValidationRule
{
private Func<bool> validation;
public ValidationRule(Func<bool> validation)
{
this.validation = validation;
}
public bool IsValid()
{
return validation();
}
}
would be more C# 3 style but is compiled to the same code as @Frank Krueger's answer. This is what you asked for, but doesn't feel right. Is there a good reason why the entity can't be extended to perform validation?
会更像 C# 3 风格,但编译成与@Frank Krueger 的答案相同的代码。这是你要求的,但感觉不对。实体不能扩展以执行验证是否有充分的理由?
回答by Jason Olson
Well, simply, if you have an Entity class, and you want to use lambda expressions on that Entity to determine if something is valid (returning boolean), you could use a Func.
好吧,简单地说,如果您有一个实体类,并且您想在该实体上使用 lambda 表达式来确定某些内容是否有效(返回布尔值),您可以使用 Func。
So, given an Entity:
因此,给定一个实体:
class Entity
{
public string MyProperty { get; set; }
}
You could define a ValidationRule class for that like this:
您可以像这样定义一个 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);
}
}
Then you could use it like this:
然后你可以像这样使用它:
var myEntity = new Entity() { MyProperty = "Hello World" };
var rule = new ValidationRule<Entity>(entity => entity.MyProperty == "Hello World");
var valid = rule.IsValid(myEntity);
Of course, that's just one possible solution.
当然,这只是一种可能的解决方案。
If you remove the generic constraint above ("where T : Entity"), you could make this a generic rules engine that could be used with any POCO. You wouldn't have to derive a class for every type of usage you need. So if I wanted to use this same class on a TextBox, I could use the following (after removing the generic constraint):
如果删除上面的通用约束(“where T : Entity”),则可以将其设为可与任何 POCO 一起使用的通用规则引擎。您不必为您需要的每种使用类型派生一个类。因此,如果我想在 TextBox 上使用相同的类,我可以使用以下内容(删除通用约束后):
var rule = new ValidationRule<TextBox>(tb => tb.Text.Length > 0);
rule.IsValid(myTextBox);
It's pretty flexible this way. Using lambda expressions and generics together is very powerful. Instead of accepting Func or Action, you could accept an Expression> or Expression> and have direct access to the express tree to automatically investigate things like the name of a method or property, what type of expression it is, etc. And people using your class would not have to change a single line of code.
这种方式非常灵活。将 lambda 表达式和泛型结合使用非常强大。除了接受 Func 或 Action,您还可以接受 Expression> 或 Expression> 并直接访问 express 树以自动调查诸如方法或属性的名称、它是什么类型的表达式等内容。类将不必更改一行代码。
回答by Rinat Abdullin
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 .NETfor more information
查看.NET 中的 DDD 和规则驱动的 UI 验证以获取更多信息