Eu sei que esta funcionalidade já existe à algum tempo e eu até já tinha usado em alguns exemplos, mas, ainda não tinha pensado em Lambda Expressions a sério.
Assim, resolvi hoje pegar em alguns exemplos e encontrar um exemplo que me sirva e tentar fazer alguma coisa. O que descobri é que é mais um nível de abstração no nosso código e em alguns casos, transforma-o em código cada vez mais dificil de ler e noutros casos facilita imenso.
Tentei resolver um problema que tenho no meu código que é a obtenção de um Entidade de diversas formas. Todos nós temos em alguma parte do nosso código as seguintes expressões: GetEntityByName ou GetEntityByEmail, onde Entity é a uma qualquer entidade da nossa aplicação e a seguir ao By temos toda e qualquer propriedade que faça sentido.
Este tipo de abordagem leva a um problema: “Magic String” espalhados no nosso código, pois se não vejamos. Nesses métodos temos habitualmente o seguinte código:
public string GetEntityByName(string name)
{
string sqlStatement = string.Format("SELECT * FROM <Entity Table> WHERE name = {0}", name);
(…)
}
ou ainda:
public string GetEntityByEmail(string name)
{
string sqlStatement = string.Format("SELECT * FROM <Entity Table> WHERE email = {0}", email);
(…)
}
Uma qualquer alteração na tabela não leva um erro em Compiletime na nossa aplicação, mas, em Runtime.
Será que não conseguimos melhorar esta abordagem usando as expressões do C# 3.0? Como?
Com este método:
protected virtual string GetEntityByProperty(Expression<Func<T, object>> expression, object value)
{
string selectedProperty = PropertyUtil.GetPropertyByName<T>(expression);
string sqlStatement = string.Format("SELECT * FROM <Entity Table> WHERE {0} = {1}", selectedProperty, value);
(…)
}
Desta forma consigo reproduzir qualquer GetObjectBy que a minha aplicação necessite. A criação da linha de comando SQL está centralizado num só método e qualquer alteração que tenha que ser feita a esta, é efectuada num só lugar.
O Helper que uso para obter a propriedade a partir de uma expressão é:
public static class PropertyUtil
{
public static string GetPropertyByName<T> (Expression<Func<T, object>> expression)
{
if (expression == null)
throw new ArgumentNullException("propertyRefExpr", "propertyRefExpr is null.");
MemberExpression memberExpr = expression.Body as MemberExpression;
if (memberExpr == null)
{
UnaryExpression unaryExpr = expression.Body as UnaryExpression;
if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
memberExpr = unaryExpr.Operand as MemberExpression;
}
if (memberExpr != null && memberExpr.Member.MemberType == MemberTypes.Property)
return memberExpr.Member.Name;
throw new ArgumentException("No property reference expression was found.", "expression");
}
}
Na minha aplicação passo a invocar este processo da seguinte forma:
public string GetEntityByName(string name)
{
var user = GetEntityByProperty(user => user.Name, name);
(…)
}
ou ainda:
public string GetEntityByName(string email)
{
var user = GetEntityByProperty(user => user.Email, email);
(…)
}
Desta, qualquer alteração no objecto User irá levar a um erro em CompileTime que podemos corrigir facilmente.
Abraços
Paulo Aboim Pinto
No comments:
Post a Comment