2015-07-20 16 views
1


我有以下情況。
我有一堆簡單的類,例如這個如何實現僅在運行時期間已知的驗證規則

public class Student 
{ 
    public int Id { get; set; } 
    public int Age { get; set; } 
    public decimal AverageMark { get; set; } 
    public string Name { get; set; } 
    public string University { get; set; } 
} 

有網頁爲他們每個人的地方,用戶可以創建,編輯和刪除。當我們創建更新它的學生時,我們需要驗證它。 問題是,我們不知道編譯期間的驗證規則!
我們爲管理員設置了獨立的網頁,例如他設置了驗證標準 ,學生年齡不能小於15歲,或者大學必須與「某些大學」平等。
至於結果,我都存儲在我的數據庫

public class Criteria 
{ 
    public string PropertyName { get; set; } 
    public string OperationName { get; set; } 
    public string OperationValue { get; set; } 
} 

我已經創建了一個調查的目的簡單的控制檯應用程序審覈規定的一些列表。這裏是代碼

namespace DynamicValidation 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     //set up students 
     var student1 = new Student() { Age = 20, AverageMark = 4, Name = "Ihor", University = "Lviv National University" }; 
     var student2 = new Student() { Age = 20, AverageMark = 4, Name = "Taras", University = "Lviv National University" }; 
     var student3 = new Student() { Age = 20, AverageMark = 5, Name = "Marko", University = "" }; 
     var student4 = new Student() { Age = 20, AverageMark = 3, Name = "Tanya", University = "" }; 
     var student5 = new Student() { Age = 22, AverageMark = 4, Name = "Ira", University = "" }; 


     var students = new List<Student>() { student1, student2, student3, student4, student5 }; 

     //set up validation rules 
     var criteria1 = new Criteria("Age", "Equal", "20"); 
     var criteria2 = new Criteria("AverageMark", "NotLessThan", "4"); 
     var criteria3 = new Criteria("University", "Contains", "Lviv"); 

     var criterias = new List<Criteria>() { criteria1, criteria2, criteria3 }; 

     var result = new List<Student>(); 
     foreach (var currentStudent in students) 
     { 
      foreach (var currentCriteria in criterias) 
      { 
       object currentPropertyValue = typeof(Student).GetProperty(currentCriteria.PropertyName).GetValue(currentStudent); 

       //what is next ???!!! 
      } 
     } 
    } 
} 

public class Student 
{ 
    public int Id { get; set; } 
    public int Age { get; set; } 
    public decimal AverageMark { get; set; } 
    public string Name { get; set; } 
    public string University { get; set; } 
} 

public class Criteria 
{ 
    public string PropertyName { get; set; } 
    public string OperationName { get; set; } 
    public string OperationValue { get; set; } 
} 

}

我如何能實現這一段代碼? (表情樹,動態?)
我不希望你爲我工作,但也許有一些關於這方面的文章? (我試圖找到但沒有成功)
也許一些關於方法的建議? 也許有一些類似的開放代碼?
或者也許它已經在一些圖書館實施?

將感謝任何幫助:)

+0

表達式樹將是最好的方式 –

+4

邊注:請求/存儲年齡通常是一個壞主意。獲得DOB然後*計算*年齡通常要合理得多(至少,如果數據預計將保持超過24小時有效) –

+0

@Damien_The_Unbeliever。你是完全正確的。我會考慮這個 – Disappointed

回答

0

恕我直言,我發現那麼一點點更好的解決方案提出
現在我們不需要改變學生類中的驗證邏輯,如果新的屬性將被添加。另外這個代碼可以被應用到任何其他類(不僅是像以前學生類)

接口驗證

public interface IValidator 
{ 
    bool Validate(object value, object validateWith); 
} 

Set實現

public class ContainsValidator : IValidator 
{ 
    public bool Validate(object value, object validateWith) 
    { 
     string valueString = Convert.ToString(value); 
     string validateWithString = Convert.ToString(validateWith); 

     return valueString.Contains(validateWithString); 
    } 
} 

public class StartWithValidator : IValidator 
{ 
    public bool Validate(object value, object validateWith) 
    { 
     string valueString = Convert.ToString(value); 
     string validateWithString = Convert.ToString(validateWith); 

     return valueString.StartsWith(validateWithString); 
    } 
} 

public class LengthValidator : IValidator 
{ 
    public bool Validate(object value, object validateWith) 
    { 
     string valueString = Convert.ToString(value); 
     int valueLength = Convert.ToInt32(validateWith); 

     return (valueString.Length == valueLength); 
    } 
} 

public class LessThanValidator : IValidator 
{ 
    public bool Validate(object value, object validateWith) 
    { 
     decimal valueDecimal = Convert.ToDecimal(value); 
     decimal validateWithDecimal = Convert.ToDecimal(validateWith); 

     return (valueDecimal < validateWithDecimal); 
    } 
} 

public class MoreThanValidator : IValidator 
{ 
    public bool Validate(object value, object validateWith) 
    { 
     decimal valueDecimal = Convert.ToDecimal(value); 
     decimal validateWithDecimal = Convert.ToDecimal(validateWith); 

     return (valueDecimal > validateWithDecimal); 
    } 
} 

public class EqualValidator : IValidator 
{ 
    public bool Validate(object value, object validateWith) 
    { 
     string valueString = Convert.ToString(value); 
     string validateWithString = Convert.ToString(validateWith); 

     return (valueString == validateWithString); 
    } 
} 

的和用法

class Program 
{ 
    static void Main(string[] args) 
    { 
     //set up students 
     var student1 = new Student() { Age = 20, AverageMark = 5, Name = "Ihor", University = "Lviv National University" }; 
     var student2 = new Student() { Age = 20, AverageMark = 5, Name = "SomeLongName", University = "Lviv National University" }; 
     var student3 = new Student() { Age = 20, AverageMark = 5, Name = "Taras", University = "Kyiv National University" }; 
     var student4 = new Student() { Age = 20, AverageMark = 5, Name = "Marko", University = "Some University" }; 
     var student5 = new Student() { Age = 20, AverageMark = 4, Name = "Tanya", University = "Lviv National University" }; 
     var student6 = new Student() { Age = 22, AverageMark = 4, Name = "Ira", University = "" }; 

     var students = new List<Student>() { student1, student2, student3, student4, student5, student6 }; 

     //set up validation rules 
     var criteria1 = new Criteria("Age", "Equal", "20"); 
     var criteria2 = new Criteria("AverageMark", "MoreThen", "4"); 
     var criteria3 = new Criteria("University", "Contains", "National"); 
     var criteria4 = new Criteria("University", "StartWith", "Lviv"); 
     var criteria5 = new Criteria("Name", "Length", "4"); 

     var criterias = new List<Criteria>() { criteria1, criteria2, criteria3, criteria4, criteria5 }; 

     var result = new List<Student>(); 
     foreach (var currentStudent in students) 
     { 
      var isValid = true; 
      foreach (var currentCriteria in criterias) 
      { 
       object currentPropertyValue = typeof(Student).GetProperty(currentCriteria.PropertyName).GetValue(currentStudent); 
       IValidator currentValidator = ValidatorFactory.GetValidator(currentCriteria.OperationName); 

       bool validationResult = currentValidator.Validate(currentPropertyValue, currentCriteria.OperationValue); 
       if (!validationResult) 
       { 
        isValid = false; 
        break; 
       } 
      } 

      if (isValid) 
       result.Add(currentStudent); 
     } 
    } 
} 

最終ValidatorFactory的代碼

public class ValidatorFactory 
{ 
    public static IValidator GetValidator(string validatorName) 
    { 
     validatorName = validatorName.ToUpper(); 
     switch (validatorName) 
     { 
      case "CONTAINS": return new ContainsValidator(); 
      case "STARTWITH": return new StartWithValidator(); 
      case "EQUAL": return new EqualValidator(); 
      case "MORETHEN": return new MoreThanValidator(); 
      case "LENGTH": return new LengthValidator(); 
      default: throw new Exception("There are not appropriate validator."); 
     } 
    } 
} 

也許這將幫助別人的未來:)

2

你可以寫一個學生的驗證功能,請參閱IsValidStudent(Criteria criteria)

public class Student 
{ 
    public int Id { get; set; } 
    public int Age { get; set; } 
    public decimal AverageMark { get; set; } 
    public string Name { get; set; } 
    public string University { get; set; } 

    public bool IsValidStudent(Criteria criteria) 
    { 
     return IsValidByAge(criteria) 
      && IsValidByMarks(criteria) 
      && IsValidByUniversity(criteria); 
    } 

    private bool IsValidByAge(Criteria criteria) 
    { 
     switch (criteria.OperationType) 
     { 
      case Criteria.Operation.GreaterThan: 
       return Convert.ToInt32(criteria.OperationValue) > this.Age; 
      case Criteria.Operation.LessThan: 
       return Convert.ToInt32(criteria.OperationValue) < this.Age; 
      case Criteria.Operation.EqualTo: 
       return Convert.ToInt32(criteria.OperationValue) == this.Age; 
      default: 
       return false; 
     } 
    } 

    private bool IsValidByMarks(Criteria criteria) 
    { 
     // etc... 
    } 

    private bool IsValidByUniversity(Criteria criteria) 
    { 
     // etc... 
    } 
} 

用法:

var result = new List<Student>(); 
foreach (var currentStudent in students) 
{ 
    foreach (var currentCriteria in criterias) 
    { 
      if (currentStudent.IsValidStudent(currentCriteria)) 
      { 
       result.Add(currentStudent); 
      } 
    } 
} 

我還延長你的Criteria類:

public class Criteria 
{ 
    public string PropertyName { get; set; } 
    public Operation OperationType { get; set; } 
    public string OperationValue { get; set; } 

    public enum Operation 
    { 
     EqualTo, 
     GreaterThan, 
     LessThan, 
     Contains 
    } 

    public Criteria(string propertyName, Operation operationType, string operationValue) 
    { 
     this.PropertyName = propertyName; 
     this.OperationType = operationType; 
     this.OperationValue = operationValue; 
    } 
} 
+0

非常感謝! :)但理想情況下,我想有更通用的東西。我的意思是。例如,如果將添加新屬性(例如Srudent.LastName),則必須添加用於驗證的新方法(並且IsValidStudent也必須更改)。此外,這段代碼不能重用(對於另一類)(我有幾個類)無論如何,非常感謝! – Disappointed

+0

也許我想要太多... – Disappointed

+0

也許你會對我的解決方案感興趣:) – Disappointed