studio - ¿Hay una solución para la falta del operador ''nameof'' en C#para el enlace de datos seguro?
visual studio code acentos (8)
Ha habido mucho sentimiento para incluir un nameof
operador en C #. Como ejemplo de cómo funcionaría este operador, nameof(Customer.Name)
devolvería la cadena "Name"
.
Tengo un objeto de dominio. Y tengo que atarlo. Y necesito nombres de propiedades como cadenas entonces. Y quiero que sean seguros de tipo.
Recuerdo encontrar una solución en .NET 3.5 que proporcionaba la funcionalidad de nameof
y expresiones lambda involucradas. Sin embargo, no he podido encontrar esta solución. ¿Alguien puede proporcionarme esa solución?
También estoy interesado en una forma de implementar la funcionalidad de nameof
en .NET 2.0 si eso es posible.
A menos que alguien cambie de parecer, el nameof
operador parece estar en C # 6. Estas son las notas de la reunión de diseño al respecto:
Este código básicamente hace eso:
class Program
{
static void Main()
{
var propName = Nameof<SampleClass>.Property(e => e.Name);
Console.WriteLine(propName);
}
}
public class Nameof<T>
{
public static string Property<TProp>(Expression<Func<T, TProp>> expression)
{
var body = expression.Body as MemberExpression;
if(body == null)
throw new ArgumentException("''expression'' should be a member expression");
return body.Member.Name;
}
}
(Por supuesto, es código 3.5 ...)
Esto es parte del lenguaje en C # 6.0
La respuesta de reshefm es bastante buena, pero esto es un poco más simple API IMO:
Ejemplo de uso: NameOf.Property(() => new Order().Status)
using System;
using System.Diagnostics.Contracts;
using System.Linq.Expressions;
namespace AgileDesign.Utilities
{
public static class NameOf
{
///<summary>
/// Returns name of any method expression with any number of parameters either void or with a return value
///</summary>
///<param name = "expression">
/// Any method expression with any number of parameters either void or with a return value
///</param>
///<returns>
/// Name of any method with any number of parameters either void or with a return value
///</returns>
[Pure]
public static string Method(Expression<Action> expression)
{
Contract.Requires<ArgumentNullException>(expression != null);
return ( (MethodCallExpression)expression.Body ).Method.Name;
}
///<summary>
/// Returns name of property, field or parameter expression (of anything but method)
///</summary>
///<param name = "expression">
/// Property, field or parameter expression
///</param>
///<returns>
/// Name of property, field, parameter
///</returns>
[Pure]
public static string Member(Expression<Func<object>> expression)
{
Contract.Requires<ArgumentNullException>(expression != null);
if(expression.Body is UnaryExpression)
{
return ((MemberExpression)((UnaryExpression)expression.Body).Operand).Member.Name;
}
return ((MemberExpression)expression.Body).Member.Name;
}
}
}
El código completo está aquí: http://agiledesignutilities.codeplex.com/SourceControl/changeset/view/b76cefa4234a#GeneralPurpose/NameOf.cs
La solución aceptada es agradable, simple y elegante.
Sin embargo, construir un árbol de expresiones es costoso, y necesito toda la ruta de la propiedad.
Así que lo cambié un poco. No es nada elegante, pero es simple y funciona bien en la mayoría de los casos:
public static string Property<TProp>(Expression<Func<T, TProp>> expression)
{
var s = expression.Body.ToString();
var p = s.Remove(0, s.IndexOf(''.'') + 1);
return p;
}
Ejemplo:
? Nameof<DataGridViewCell>.Property(c => c.Style.BackColor.A);
"Style.BackColor.A"
La solución consiste en utilizar un árbol de expresiones y separar ese árbol de expresiones para encontrar el MemberInfo
relevante. Hay un poco más de detalles y comentarios en esta nota (aunque no el código para sacar al miembro, eso está en otra pregunta de SO en algún lado, creo).
Desafortunadamente, como los árboles de expresión no existen en .NET 2.0, realmente no hay equivalente.
Una solución para evitar errores tipográficos es tener un conjunto de accesadores que capturen el PropertyInfo
relevante para una propiedad en particular, y que la unidad los pruebe. Ese sería el único lugar que tenía la cuerda. Esto evitaría la duplicación y facilitaría la refactorización, pero es un poco draconiano.
Mientras que reshefm y Jon Skeet muestran la forma correcta de hacer esto usando expresiones, vale la pena señalar que hay una forma más económica de hacer esto para los nombres de métodos:
Envuelva a un delegado en su método, obtenga MethodInfo y estará listo. Aquí hay un ejemplo:
private void FuncPoo()
{
}
...
// Get the name of the function
string funcName = new Action(FuncPoo).Method.Name;
Lamentablemente, esto solo funciona por métodos; no funciona para las propiedades, ya que no puede tener delegados en los métodos getter o setter de la propiedad. (Parece una limitación tonta, IMO.)
Una extensión de lo que hizo Reshefm, que simplificó el uso del operador name of () y también proporciona los nombres de los métodos y miembros y métodos de la clase:
/// <summary>
/// Provides the <see cref="nameof"/> extension method that works as a workarounds for a nameof() operator,
/// which should be added to C# sometime in the future.
/// </summary>
public static class NameOfHelper
{
/// <summary>
/// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression.
/// </summary>
/// <typeparam name="T">The type of the <paramref name="obj"/> parameter.</typeparam>
/// <typeparam name="TProp">The type of the property (or the method''s return type), which is used in the <paramref name="expression"/> parameter.</typeparam>
/// <param name="obj">An object, that has the property (or method), which its name is returned.</param>
/// <param name="expression">A Lambda expression of this pattern: x => x.Property <BR/>
/// Where the x is the <paramref name="obj"/> and the Property is the property symbol of x.<BR/>
/// (For a method, use: x => x.Method()</param>
/// <returns>A string that has the name of the given property (or method).</returns>
public static string nameof<T, TProp>(this T obj, Expression<Func<T, TProp>> 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");
}
/// <summary>
/// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression.
/// </summary>
/// <typeparam name="TProp">The type of the property (or the method''s return type), which is used in the <paramref name="expression"/> parameter.</typeparam>
/// <param name="expression">A Lambda expression of this pattern: () => x.Property <BR/>
/// Where Property is the property symbol of x.<BR/>
/// (For a method, use: () => x.Method()</param>
/// <returns>A string that has the name of the given property (or method).</returns>
public static string nameof<TProp>(Expression<Func<TProp>> 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 usarlo:
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.
}
}