Solução alternativa para a falta de ‘nameof’ operador em c # para binding de dados de tipo seguro?

Tem havido muito sentimento para include um nameof operador em C #. Como exemplo de como esse operador funcionaria, nameof(Customer.Name) retornaria a string "Name" .

Eu tenho um object de domínio. E eu tenho que ligá-lo. E preciso de nomes de propriedades como strings então. E eu quero que eles sejam seguros para o tipo.

Lembro-me de encontrar uma solução alternativa no .NET 3.5 que forneceu a funcionalidade de nameof e envolveu expressões lambda. No entanto, não consegui localizar essa solução alternativa. Alguém pode fornecer essa solução para mim?

Também estou interessado em uma maneira de implementar a funcionalidade de nameof no .NET 2.0, se isso for possível.

Este código basicamente faz isso:

 class Program { static void Main() { var propName = Nameof.Property(e => e.Name); Console.WriteLine(propName); } } public class Nameof { public static string Property(Expression> expression) { var body = expression.Body as MemberExpression; if(body == null) throw new ArgumentException("'expression' should be a member expression"); return body.Member.Name; } } 

(Claro que é código 3.5 …)

Enquanto reshefm e Jon Skeet mostram a maneira correta de fazer isso usando expressões, vale a pena notar que existe uma maneira mais barata de fazer isso para nomes de methods:

Envolva um delegado em torno de seu método, obtenha o MethodInfo e você é bom para ir. Aqui está um exemplo:

 private void FuncPoo() { } ... // Get the name of the function string funcName = new Action(FuncPoo).Method.Name; 

Infelizmente, isso funciona apenas para methods; ele não funciona para propriedades, pois você não pode ter delegates para os methods getter ou setter de propriedade. (Parece uma limitação tola, IMO.)

A solução alternativa é usar uma tree de expressão e desmembrar essa tree de expressões para localizar o MemberInfo relevante. Há um pouco mais de detalhes e comentários nesta nota (embora não o código para retirar o membro – que está em outra pergunta SO em algum lugar, eu acredito).

Infelizmente, como as trees de expressão não existem no .NET 2.0, não há realmente nenhum equivalente.

Uma solução para evitar erros de digitação é ter um conjunto de acessadores que buscam o PropertyInfo relevante para uma propriedade específica e testá-los na unidade. Esse seria o único lugar que tinha a corda nela. Isso evitaria duplicação e tornaria a refatoração mais fácil, mas é um pouco draconiana.

Uma extensão do que reshefm fazia, que simplificava o uso do operador nameof () e dava os nomes dos methods e membros da class e methods também:

 ///  /// Provides the  extension method that works as a workarounds for a nameof() operator, /// which should be added to C# sometime in the future. ///  public static class NameOfHelper { ///  /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression. ///  /// The type of the  parameter. /// The type of the property (or the method's return type), which is used in the  parameter. /// An object, that has the property (or method), which its name is returned. /// A Lambda expression of this pattern: x => x.Property 
/// Where the x is the and the Property is the property symbol of x.
/// (For a method, use: x => x.Method() /// A string that has the name of the given property (or method). public static string nameof(this T obj, Expression> expression) { MemberExpression memberExp = expression.Body as MemberExpression; if (memberExp != null) return memberExp.Member.Name; MethodCallExpression methodExp = expression.Body as MethodCallExpression; if (methodExp != null) return methodExp.Method.Name; throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression"); } /// /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression. /// /// The type of the property (or the method's return type), which is used in the parameter. /// A Lambda expression of this pattern: () => x.Property
/// Where Property is the property symbol of x.
/// (For a method, use: () => x.Method() /// A string that has the name of the given property (or method). public static string nameof(Expression> expression) { MemberExpression memberExp = expression.Body as MemberExpression; if (memberExp != null) return memberExp.Member.Name; MethodCallExpression methodExp = expression.Body as MethodCallExpression; if (methodExp != null) return methodExp.Method.Name; throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression"); } }

Para usá-lo:

 static class Program { static void Main() { string strObj = null; Console.WriteLine(strObj.nameof(x => x.Length)); //gets the name of an object's property. Console.WriteLine(strObj.nameof(x => x.GetType())); //gets the name of an object's method. Console.WriteLine(NameOfHelper.nameof(() => string.Empty)); //gets the name of a class' property. Console.WriteLine(NameOfHelper.nameof(() => string.Copy(""))); //gets the name of a class' method. } } 

A menos que alguém mude de ideia, o nameof operador parece estar em C # 6. Aqui estão as annotations da reunião de design sobre isso:

https://roslyn.codeplex.com/discussions/552376

https://roslyn.codeplex.com/discussions/552377

A solução aceita é legal, simples e elegante.

No entanto, construir uma tree de expressão é caro e preciso de todo o caminho da propriedade.

Então eu mudei um pouco. Não é nada elegante, mas é simples e funciona bem na maioria dos casos:

 public static string Property(Expression> expression) { var s = expression.Body.ToString(); var p = s.Remove(0, s.IndexOf('.') + 1); return p; } 

Exemplo:

 ? Nameof.Property(c => c.Style.BackColor.A); "Style.BackColor.A" 

Isso faz parte do idioma no C # 6.0

https://msdn.microsoft.com/pt-br/magazine/dn802602.aspx

A resposta do reshefm é muito boa, mas isso é um pouco mais simples da API do IMO:

Exemplo de uso: NameOf.Property(() => new Order().Status)

 using System; using System.Diagnostics.Contracts; using System.Linq.Expressions; namespace AgileDesign.Utilities { public static class NameOf { /// /// Returns name of any method expression with any number of parameters either void or with a return value /// /// /// Any method expression with any number of parameters either void or with a return value /// /// /// Name of any method with any number of parameters either void or with a return value /// [Pure] public static string Method(Expression expression) { Contract.Requires(expression != null); return ( (MethodCallExpression)expression.Body ).Method.Name; } /// /// Returns name of property, field or parameter expression (of anything but method) /// /// /// Property, field or parameter expression /// /// /// Name of property, field, parameter /// [Pure] public static string Member(Expression> expression) { Contract.Requires(expression != null); if(expression.Body is UnaryExpression) { return ((MemberExpression)((UnaryExpression)expression.Body).Operand).Member.Name; } return ((MemberExpression)expression.Body).Member.Name; } } } 

O código completo está aqui: http://agiledesignutilities.codeplex.com/SourceControl/changeset/view/b76cefa4234a#GeneralPurpose/NameOf.cs