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

C# 使用表达式获取POCO对象属性的名称和值,c#,lambda,expression,poco,C#,Lambda,Expression,Poco,我正在寻找一种方法来获取POCO对象中property的名称和值。我尝试过许多解决方案,但似乎都无法奏效。我真的很喜欢旧的解决方案,但它会导致null ref错误 以下是我想做的: public class POCO { public int ID { get; set; } public string Name { get; set; } public string Surname { get; set; } public

我正在寻找一种方法来获取POCO对象中property的名称和值。我尝试过许多解决方案,但似乎都无法奏效。我真的很喜欢旧的解决方案,但它会导致null ref错误

以下是我想做的:

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();
    }
}
公共类POCO
{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共字符串姓氏{get;set;}
公共字符串说明{get;set;}
}
公共类POCOValidationResult
{
公共bool有效{get;set;}
公共字符串错误{get;set;}
}
公共抽象类验证器,其中T:class
{
公共T实体{get;set;}
公共摘要POCOValidationResult Validate();
受保护的POCOValidationResult ValidateStringPropertyToLengthOf(表达式表达式,int-maxLength)
{
var propertyName=getPropertyName(表达式);
var propertyValue=getPropertyValue(表达式);
如果(propertyValue.Length>maxLength)
{
返回新的POCOValidationResult()
{
Error=string.Format(“{0}值太长。必须小于或等于{1}”,propertyName,maxLength.ToString()
};
}
返回新的POCOValidationResult(){IsValid=true};
}
内部字符串getPropertyName(表达式)
{
var memberExpersion=(MemberExpression)expression.Body;
返回memberExpersion.Member.Name;
}
内部字符串getPropertyValue(表达式)
{
//努力让它工作
var me=(MemberExpression)expression.Body;//(MemberExpression)((MemberExpression)expression.Body.expression;
var ce=(ConstantExpression)me.Expression;//此处出错!
var fieldInfo=ce.Value.GetType().GetField(me.Member.Name,BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var值=fieldInfo.GetValue(ce.value);
}
}
公共类POCOValidator:验证器
{
公共覆盖POCOValidationResult Validate()
{
var姓氏ValidationResult=ValidateStringPropertyToLengthOf(p=>p.姓氏,10);
如果(!namesvalidationresult.IsValid)
返回验证结果;
//var descriptionValidationResult=ValidateStringPropertyToLengthOf(p=>p.Description,100);
//如果(!descriptionValidationResult.IsValid)
//返回descriptionValidationResult;
//var nameValidationResult=ValidateStringPropertyToLengthOf(p=>p.Name,15);
//如果(!nameValidationResult.IsValid)
//返回nameValidationResult;
返回新的POCOValidationResult(){IsValid=true};
}
}
公营工人
{
public void ImDoingWorkReally()
{
var pocovalidation=新的POCOValidator()
{
实体=新POCO()
{ 
ID=1,
Name=“詹姆斯”,
姓氏=“院长”,
Description=“我不是007!”
}
};
var vallidationResult=pocovalliation.Validate();
如果(!vallidationResult.IsValid)
{
返回;
}
//继续工作。。。
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var workerBee=新workerBee();
workerBee.ImDoingWorkReally();
}
}
如您所见,我尝试获取属性的名称和值[通过使用表达式
(p=>p.lasname)
作为方法
ValidateStringPropertyToLengthOf(…)
]中的参数]。问题是,当调用
var ce=(ConstantExpression)me.Expression时,我在
getPropertyValue(Expression)
中得到一个null ref错误

那么,有没有人对如何让它发挥作用有想法

谢谢你花时间来调查这件事。我真的很感激这一点,希望我的问题也能对其他人有所帮助,因为我认为如果我能让它发挥作用,这会非常有用

编辑:我在注释中进行了如下更改,但在运行单元测试时仍然出现错误“无法将'System.Linq.Expressions.TypedParameterExpression'类型的对象强制转换为'System.Linq.Expressions.ConstantExpression'。

我制定了一个解决方案(遗憾的是注释没有帮助)。以下是有效的代码:

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

我相信这可以解释问题,如果是这样的话,请删除你的问题。我觉得这看起来像是重复的。根据leppie的建议,您应该将方法声明更改为
string getPropertyValue(Expression Expression)
,以便传递正确的表达式类型(即带有主体的表达式)。我会花5分钟亲自测试它,但您没有费心包括在内。我感谢您的帮助,但更改声明没有帮助,因为我仍然会遇到相同的错误:“无法将'System.Linq.Expressions.TypedParameterExpression'类型的对象强制转换为'System.Linq.Expressions.ConstantExpression'类型。”
    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();
    }