我正在尝试使用linq表达式来验证我的MVC代码中的电话号码。代码看起来像这样:
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 :(得分: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 )
....
}
答案 1 :(得分: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; }
}