2015-03-03 2 views
1

Я ищу способ получить имя и ценность протеи в объекте POCO. Я пробовал много решений, но не могу заставить их работать. Мне очень понравилось this старое решение, но оно вызывает ошибку null ref.Получить имя и значение свойства объекта POCO с помощью выражения

Вот вроде того, что я пытаюсь сделать:

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

Так как вы можете видеть, я пытаюсь получить имя и значение свойства [с помощью Expression (p => p.Surname) в качестве параметра в способ ValidateStringPropertyToLengthOf(...)]. Проблема в том, что я получаю ошибку null ref в getPropertyValue(Expression<Func<T, object>> expression), когда он вызывает var ce = (ConstantExpression)me.Expression;

У кого-нибудь есть идеи о том, как заставить это работать?

Спасибо, что нашли время, чтобы изучить это. Я очень ценю это и надеюсь, что мой вопрос также будет полезен для других, поскольку я думаю, что это может быть весьма полезно, если я смогу заставить это работать.

EDIT: Я сделал изменения, как указано ниже в комментариях и по-прежнему получаю сообщение об ошибке «Не удается привести объект типа„System.Linq.Expressions.TypedParameterExpression“к типу«System.Linq.Expressions. ConstantExpression ", когда я запускаю свой модульный тест.

+3

Я уверен, что это будет объяснить проблему http://stackoverflow.com/questions/3567857/why-are- some-object-properties-unaryexpression-and-others-memberexpression/3573250 # 3573250 Пожалуйста, удалите свой вопрос, если это так. – leppie

+0

Это похоже на дубликат для меня. По совету leppie вы должны изменить объявление метода на 'string getPropertyValue (выражение > выражение)', чтобы был передан правильный тип выражения (т. Е. Один с телом). Я потратил 5 минут, чтобы проверить его сам, но вы не потрудились включить [минимальный, полный пример кода] (http://stackoverflow.com/help/mcve). –

+0

Я ценю помощь, но изменение объявления не помогло, так как я все еще получаю ту же ошибку: «Невозможно передать объект типа« System.Linq.Expressions.TypedParameterExpression »для ввода« System.Linq.Expressions.ConstantExpression ». " – MaudDib

ответ

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(); 
    } 
Смежные вопросы