使用表达式获取POCO对象的属性的名称和值

时间:2015-03-03 07:44:30

标签: c# lambda expression poco

我正在寻找一种方法来获取POCO对象中的一个proptery的名称和价值。我尝试了很多解决方案,但似乎无法让它们发挥作用。我真的很喜欢this旧解决方案,但它会导致空引用错误。

以下是我尝试做的事情:

public class POCO
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
        public string Description { get; set; }
    }

public class POCOValidationResult
{
    public bool IsValid { get; set; }
    public string Error { get; set; }
}

public abstract class Validator<T> where T : class
{
    public T Entity { get; set; }

    public abstract POCOValidationResult Validate();

    protected POCOValidationResult ValidateStringPropertyToLengthOf(Expression<Func<T, object>> expression, int maxLength)
    {
        var propertyName = getPropertyName(expression);
        var propertyValue = getPropertyValue(expression);

        if (propertyValue.Length > maxLength)
        {
            return new POCOValidationResult()
            {
                Error = string.Format("{0} value is too long. Must be less or equal to {1}", propertyName, maxLength.ToString())
            };
        }

        return new POCOValidationResult() { IsValid = true };
    }

    internal string getPropertyName(Expression<Func<T, object>> expression)
    {
        var memberExpersion = (MemberExpression)expression.Body;

        return memberExpersion.Member.Name;
    }
    internal string getPropertyValue<R>(Expression<Func<T, R>> expression)
    {
        //struggling to get this to work

        var me = (MemberExpression)expression.Body; // (MemberExpression)((MemberExpression)expression.Body).Expression;
        var ce = (ConstantExpression)me.Expression; // Error here!
        var fieldInfo = ce.Value.GetType().GetField(me.Member.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        var value = fieldInfo.GetValue(ce.Value);
    }
}

public class POCOValidator : Validator<POCO>
{
    public override POCOValidationResult Validate()
    {
        var surnameValidationResult = ValidateStringPropertyToLengthOf(p => p.Surname, 10);

        if (!surnameValidationResult.IsValid)
            return surnameValidationResult;

        //var descriptionValidationResult = ValidateStringPropertyToLengthOf(p => p.Description, 100);

        //if (!descriptionValidationResult.IsValid)
        //    return descriptionValidationResult;

        //var nameValidationResult = ValidateStringPropertyToLengthOf(p => p.Name, 15);

        //if (!nameValidationResult.IsValid)
        //    return nameValidationResult;

        return new POCOValidationResult() { IsValid = true };
    }
}

public class WorkerBee
{
    public void ImDoingWorkReally()
    {
        var pocoVallidation = new POCOValidator()
        {
            Entity = new POCO()
            { 
                ID = 1, 
                Name = "James", 
                Surname = "Dean", 
                Description = "I'm not 007!"
            }
        };

        var vallidationResult = pocoVallidation.Validate();

        if (!vallidationResult.IsValid)
        {
            return;
        }

        //continue to do work...
    }
}

class Program
{
    static void Main(string[] args)
    {
        var workerBee = new WorkerBee();

        workerBee.ImDoingWorkReally();
    }
}

正如您所看到的,我试图通过使用表达式(p => p.Surname)作为方法ValidateStringPropertyToLengthOf(...)中的参数来获取属性的名称和值。问题是我在调用getPropertyValue(Expression<Func<T, object>> expression)

var ce = (ConstantExpression)me.Expression;收到空引用错误

所有人都有关于如何使其发挥作用的想法吗?

感谢您抽出宝贵时间来研究这个问题。我真的很感激,并希望我的问题对其他人也有帮助,因为我认为如果能让这个工作起作用,这可能会非常有用。

编辑:我已在评论中进行了如下所述的更改,但仍然收到错误&#34;无法投放类型&#39; System.Linq.Expressions的对象.TypedParameterExpression&#39;输入&#39; System.Linq.Expressions.ConstantExpression&#34;当我进行单元测试时。

1 个答案:

答案 0 :(得分:0)

我制定了一个解决方案(不幸的是评论没有帮助)。以下是有效的代码:

public class POCO
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Description { get; set; }
}

public class POCOValidationResult
{
    public bool IsValid { get; set; }
    public string Error { get; set; }
}

public abstract class Validator<T> where T : class
{
    public T Entity { get; set; }

    public abstract POCOValidationResult Validate();

    protected POCOValidationResult ValidateStringPropertyToLengthOf(Expression<Func<T, object>> expression, int maxLength)
    {
        var propertyName = getPropertyName(expression);
        var propertyValue = getPropertyValue(expression);

        if (propertyValue.Length > maxLength)
        {
            return new POCOValidationResult()
            {
                Error = string.Format("{0} value is too long. Must be less or equal to {1}", propertyName, maxLength.ToString())
            };
        }

        return new POCOValidationResult() { IsValid = true };
    }

    internal string getPropertyName(Expression<Func<T, object>> expression)
    {
        var memberExpersion = (MemberExpression)expression.Body;

        return memberExpersion.Member.Name;
    }
    internal string getPropertyValue(Expression<Func<T, object>> expression)
    {
        var memberExpression = expression.Body as MemberExpression;
        var propertyInfo = memberExpression.Member as PropertyInfo;

        return propertyInfo.GetValue(Entity, null).ToString();
    }
}

public class POCOValidator : Validator<POCO>
{
    public override POCOValidationResult Validate()
    {
        var surnameValidationResult = ValidateStringPropertyToLengthOf(p => p.Surname, 10);

        if (!surnameValidationResult.IsValid)
            return surnameValidationResult;

        var descriptionValidationResult = ValidateStringPropertyToLengthOf(p => p.Description, 100);

        if (!descriptionValidationResult.IsValid)
            return descriptionValidationResult;

        var nameValidationResult = ValidateStringPropertyToLengthOf(p => p.Name, 15);

        if (!nameValidationResult.IsValid)
            return nameValidationResult;

        return new POCOValidationResult() { IsValid = true };
    }
}

public class WorkerBee
{
    public void ImDoingWorkReally()
    {
        var pocoVallidation = new POCOValidator()
        {
            Entity = new POCO()
            {
                ID = 1,
                Name = "James",
                Surname = "Dean",
                Description = "I'm not 007!"
            }
        };

        var vallidationResult = pocoVallidation.Validate();

        if (!vallidationResult.IsValid)
        {
            return;
        }

        //continue to do work...
    }
}

class Program
{
    static void Main(string[] args)
    {
        var workerBee = new WorkerBee();

        workerBee.ImDoingWorkReally();
    }
}

请注意getPropertyValue的更改:

    internal string getPropertyValue(Expression<Func<T, object>> expression)
    {
        var memberExpression = expression.Body as MemberExpression;
        var propertyInfo = memberExpression.Member as PropertyInfo;

        return propertyInfo.GetValue(Entity, null).ToString();
    }