【问题标题】:C# Lambda Expressions or Delegates as a Properties or ArgumentsC# Lambda 表达式或委托作为属性或参数
【发布时间】:2008-09-26 21:28:41
【问题描述】:

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

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

【问题讨论】:

    标签: c# lambda


    【解决方案1】:

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

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

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

    【讨论】:

    • 我认为使用 Predicate 可能比 Func
    • 啊,是的,谓词很棒,基本上是一样的。
    【解决方案2】:
    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; }
        }
    }
    

    【讨论】:

      【解决方案3】:

      好吧,简单地说,如果您有一个实体类,并且您想在该实体上使用 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 树以自动调查方法或属性的名称、它是什么类型的表达式等。类不必更改一行代码。

      【讨论】:

        【解决方案4】:

        类似:

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

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

        【讨论】:

          【解决方案5】:

          这样的规则定义语法对您有用吗?

            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 and Rule driven UI Validation in .NET了解更多信息

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-03-06
            • 1970-01-01
            • 2010-10-30
            • 2011-08-14
            • 1970-01-01
            • 1970-01-01
            • 2015-01-25
            • 1970-01-01
            相关资源
            最近更新 更多