在LINQ表达式中获取属性值

4

我正在尝试在我的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 )
                    ....
    }
}

我对这里需要的语法不是很清楚。我需要怎么做才能拥有一个函数,在其中传递一个成员属性表达式,并访问该属性的名称和值。


我认为你提供的代码不会编译(我指的不是“....”)。这是你尝试解决问题的实际代码吗? - M.Babcock
为什么要重新发明轮子,当有这么多方法来验证属性呢? - Eranga
2个回答

2
在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 )
                ....
}

0

仅通过反射,您就可以获得您想要的东西。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接