2012-02-08 29 views
3

我正在尝试使用linq表达式来验证我的MVC代码中的电话号码。代码看起来像这样:在linq表达式中获取属性值

class Person 
{ 
    public HomePhone { get; set; } 
} 

class Employee 
{ 
    public WorkPhone { get; set; } 
} 

class Office 
{ 
    Employee Boss { get; set; } 
} 

class PersonController : Controller 
{ 
    private static ValidatePhoneNumber<M>(Exression<Func<M,string>> propExpr) 
    { 
     var member = prop.Body as MemberExpression; 
     if (member == null) 
     { 
      throw new ArgumentException("expression must be a member expression, i.e., x => x.MyProperty"); 
     } 

     var propInfo = member.Member as PropertyInfo; 
     if (propInfo == null) 
     { 
      throw new ArgumentException("expression is not a property type."); 
     } 

     var getter = propExpr.Compile(); 
     string phoneStr = getter(); //this doesn't work 

     if(!/* ... phoneStr is valid phone number */) 
     { 
      var propName = propInfo.Name; 
      ModelState[propName] = "invalid format for phone number"; 
     } 
    } 

    public ActionResult Create(Person p) 
    { 
     ValidatePhoneNumber(p => p.HomePhone); 
        if(ModelState.IsValid) 
        .... 
    } 

    public ActionResult CreatOffice(Office o) 
    { 
     ValidatePhoneNumber(o => o.Boss.WorkPhone); 
        if(ModelState.IsValid) 
        .... 
    } 
} 

我无法完全掌握这里所需的语法。我需要做什么才能让我有一个函数传入成员属性表达式,并且可以访问该属性的名称及其值。

+0

我不认为你提供的代码可以编译(没有我不是在谈论'....')。这是你试图解决你的问题的实际代码? – 2012-02-08 00:37:34

+0

为什么当有很多方法来验证属性时,你想重新发明轮子? – Eranga 2012-02-08 00:40:25

回答

0

你可以单独使用Reflection来获得你想要的效果。

namespace Forums.LinqToValidatePhoneNumberProperty 
{ 
    using System; 
    using System.Linq; 
    using System.Reflection; 
    using System.Text.RegularExpressions; 

    public class PhoneNumberRule 
    { 
     #region Fields 

     static string _usPhonePattern = @"1?\W*([2-9][0-8][0-9])" + 
             @"\W*([2-9][0-9]{2})\W*" + 
             @"([0-9]{4})(\se?x?t?(\d*))?"; 
     static Regex _usPhoneRegex = new Regex(_usPhonePattern); 

     #endregion Fields 

     #region Methods 

     public static void Validate(object target, string propertyName) 
     { 
      Type targetType = target.GetType(); 
      PropertyInfo targetProperty = 
       (from propertyInfo in targetType.GetProperties() 
       where (propertyInfo.Name == propertyName 
       && propertyInfo.PropertyType.IsAssignableFrom( 
        typeof (string))) 
       select propertyInfo).First(); 

      if (targetProperty == null) 
      { 
       throw new InvalidOperationException("No appropriate property " + 
                "could be found on the " + 
                "target object."); 
      } 

      string testValue = targetProperty.GetValue(target, null) as string; 

      if (testValue != null && _usPhoneRegex.IsMatch(testValue)) 
      { 
       return; 
      } 
      else 
      { 
       ModelState[propertyName] = "Not a valid phone number format"; 
      } 
     } 

     #endregion Methods 
    } 
} 

更强大的解决方案可能是使用反射和自定义属性的组合。

public class PhoneNumberRule 
    { 
     #region Fields 

     static string _usPhonePattern = @"1?\W*([2-9][0-8][0-9])" + 
             @"\W*([2-9][0-9]{2})\W*" + 
             @"([0-9]{4})(\se?x?t?(\d*))?"; 
     static Regex _usPhoneRegex = new Regex(_usPhonePattern); 

     #endregion Fields 

     #region Methods 

     public static void ValidateProperties(object target) 
     { 
      Type targetType = target.GetType(); 
      var phoneNumberProperties = 
       from propertyInfo in targetType.GetProperties() 
       where propertyInfo.GetCustomAttributes(
        typeof(PhoneNumberAttribute), true).Length > 0 
       select propertyInfo; 
      foreach (PropertyInfo targetProperty in phoneNumberProperties) 
      { 
       string value = targetProperty.GetValue(target, null) as string; 
       if (value == null || !_usPhoneRegex.IsMatch(value)) 
       { 
        ModelState[ targetProperty.Name ] = "Not a valid phone number format"; 
       } 
      } 
     } 

    } 

    [AttributeUsage(AttributeTargets.Property)] 
    public class PhoneNumberAttribute : Attribute 
    { 
    } 

    public class Person 
    { 
     [PhoneNumber()] 
     public string HomePhone { get; set; } 
    } 
1

您在Create和CreatOffice方法中声明的p和o与您在lambda表达式中声明的p和o不同。事实上,你应该得到一个错误,因为标识符已经存在于当前范围内。

我会修改你的方法是一个扩展方法。 (它需要在静态类中定义)

public static ValidatePhoneNumber<M>(this M obj, Expression<Func<M,string>> propExpr) 

然后,您可以从'obj'访问属性值。所获得的价值会是这样的......

propertyInfo.GetValue(obj, null); 

您的使用将被修改,以...

public ActionResult Create(Person p) 
{ 
    p.ValidatePhoneNumber(person => person.HomePhone); 
       if(ModelState.IsValid) 
       .... 
} 
相关问题