C#Lambda表达式或代理作为属性或参数

时间:2022-06-21 22:32:02

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.

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

5 个解决方案

#1


6  

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>

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

you could store them in a List<Func<T,bool>>.

你可以将它们存储在List >中。

#2


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

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

#3


2  

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.

好吧,简单地说,如果你有一个Entity类,并且你想在该Entity上使用lambda表达式来确定某些东西是否有效(返回boolean),你可以使用一个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,并可以直接访问表达式树以自动调查方法或属性的名称,表达的表达方式等等。并且人们使用您的class不必更改单行代码。

#4


1  

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的答案相同的代码。这就是你要求的,但感觉不对。是否有充分的理由说明实体无法扩展以执行验证?

#5


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

有关更多信息,请查看.NET中的DDD和规则驱动的UI验证

#1


6  

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>

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

you could store them in a List<Func<T,bool>>.

你可以将它们存储在List >中。

#2


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

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

#3


2  

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.

好吧,简单地说,如果你有一个Entity类,并且你想在该Entity上使用lambda表达式来确定某些东西是否有效(返回boolean),你可以使用一个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,并可以直接访问表达式树以自动调查方法或属性的名称,表达的表达方式等等。并且人们使用您的class不必更改单行代码。

#4


1  

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的答案相同的代码。这就是你要求的,但感觉不对。是否有充分的理由说明实体无法扩展以执行验证?

#5


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

有关更多信息,请查看.NET中的DDD和规则驱动的UI验证