c# - property - nameof does not exist in the current context
¿Cuál es el propósito de nameof? (15)
¿Qué sucede con los casos en los que desea reutilizar el nombre de una propiedad, por ejemplo, cuando lanza una excepción basada en un nombre de propiedad o maneja un evento
PropertyChanged
?
Existen numerosos casos en los que desea tener el nombre de la propiedad.
Toma este ejemplo:
switch (e.PropertyName)
{
case nameof(SomeProperty):
{ break; }
// opposed to
case "SomeOtherProperty":
{ break; }
}
En el primer caso, cambiar el nombre de
SomeProperty
también cambiará el nombre de la propiedad, o interrumpirá la compilación.
El último caso no.
Esta es una manera muy útil de mantener su código compilado y libre de errores (más o menos).
(Un
muy buen artículo de Eric Lippert
por qué
infoof
no lo logró, mientras que
nameof
sí)
La versión 6.0 tiene una nueva característica de
nameof
, pero no puedo entender el propósito, ya que solo toma el nombre de la variable y lo cambia a una cadena en la compilación.
Pensé que podría tener algún propósito cuando uso
<T>
pero cuando intento
nameof(T)
simplemente me imprime una
T
lugar del tipo usado.
¿Alguna idea sobre el propósito?
Anteriormente estábamos usando algo así:
// Some form.
SetFieldReadOnly( () => Entity.UserName );
...
// Base form.
private void SetFieldReadOnly(Expression<Func<object>> property)
{
var propName = GetPropNameFromExpr(property);
SetFieldsReadOnly(propName);
}
private void SetFieldReadOnly(string propertyName)
{
...
}
Motivo: seguridad en el tiempo de compilación. Nadie puede renombrar silenciosamente la propiedad y romper la lógica del código. Ahora podemos usar nameof ().
Como otros ya han señalado, el operador
nameof
inserta el nombre que se le dio al elemento en el código fuente.
Me gustaría agregar que esta es una muy buena idea en términos de refactorización, ya que hace que esta refactorización de cadenas sea segura.
Anteriormente, utilicé un método estático que utilizaba la reflexión para el mismo propósito, pero que tiene un impacto en el rendimiento del tiempo de ejecución.
El
nameof
operador no tiene impacto en el rendimiento del tiempo de ejecución;
hace su trabajo en tiempo de compilación.
Si observa el código
MSIL
, encontrará la cadena incrustada.
Consulte el siguiente método y su código desmontado.
static void Main(string[] args)
{
Console.WriteLine(nameof(args));
Console.WriteLine("regular text");
}
// striped nops from the listing
IL_0001 ldstr args
IL_0006 call System.Void System.Console::WriteLine(System.String)
IL_000C ldstr regular text
IL_0011 call System.Void System.Console::WriteLine(System.String)
IL_0017 ret
Sin embargo, eso puede ser un inconveniente si planea ofuscar su software. Después de la ofuscación, la cadena incrustada ya no puede coincidir con el nombre del elemento. Los mecanismos que dependen de este texto se romperán. Ejemplos de eso, incluidos, entre otros, son: Reflection, NotifyPropertyChanged ...
Determinar el nombre durante el tiempo de ejecución cuesta algo de rendimiento, pero es seguro para la ofuscación.
Si la ofuscación no es necesaria ni planificada, recomendaría usar el
nameof
operador.
El caso de uso más común que se me ocurre es cuando trabajo con la interfaz
INotifyPropertyChanged
.
(Básicamente, todo lo relacionado con WPF y enlaces utiliza esta interfaz)
Echale un vistazo a éste ejemplo:
public class Model : INotifyPropertyChanged
{
// From the INotifyPropertyChanged interface
public event PropertyChangedEventHandler PropertyChanged;
private string foo;
public String Foo
{
get { return this.foo; }
set
{
this.foo = value;
// Old code:
PropertyChanged(this, new PropertyChangedEventArgs("Foo"));
// New Code:
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));
}
}
}
Como puede ver en la forma anterior, tenemos que pasar una cadena para indicar qué propiedad ha cambiado.
Con
nameof
podemos usar el nombre de la propiedad directamente.
Esto podría no parecer un gran problema.
Pero imagina lo que sucede cuando alguien cambia el nombre de la propiedad
Foo
.
Cuando use una cadena, el enlace dejará de funcionar, pero el compilador no le avisará.
Cuando usa nameof, obtiene un error del compilador de que no hay propiedad / argumento con el nombre
Foo
.
Tenga en cuenta que algunos marcos usan algo de magia de reflexión para obtener el nombre de la propiedad, pero ahora tenemos el nombre de esto ya no es necesario .
El propósito del operador
nameof
es proporcionar el nombre de origen de los artefactos.
Por lo general, el nombre de origen es el mismo nombre que el nombre de metadatos:
public void M(string p)
{
if (p == null)
{
throw new ArgumentNullException(nameof(p));
}
...
}
public int P
{
get
{
return p;
}
set
{
p = value;
NotifyPropertyChanged(nameof(P));
}
}
Pero esto puede no ser siempre el caso:
using i = System.Int32;
...
Console.WriteLine(nameof(i)); // prints "i"
O:
public static string Extension<T>(this T t)
{
return nameof(T); returns "T"
}
Un uso que le he estado dando es para nombrar recursos:
[Display(
ResourceType = typeof(Resources),
Name = nameof(Resources.Title_Name),
ShortName = nameof(Resources.Title_ShortName),
Description = nameof(Resources.Title_Description),
Prompt = nameof(Resources.Title_Prompt))]
El hecho es que, en este caso, ni siquiera necesitaba las propiedades generadas para acceder a los recursos, pero ahora tengo un tiempo de compilación para verificar que los recursos existan.
El proyecto ASP.NET Core MVC usa
nameof
en
AccountController.cs
y
AccountController.cs
con el método
RedirectToAction
para hacer referencia a una acción en el controlador.
Ejemplo:
return RedirectToAction(nameof(HomeController.Index), "Home");
Esto se traduce en:
return RedirectToAction("Index", "Home");
y lleva al usuario a la acción ''Índice'' en el controlador ''Inicio'', es decir,
/Home/Index
.
El uso más común será en la validación de entrada, como
//Currently
void Foo(string par) {
if (par == null) throw new ArgumentNullException("par");
}
//C# 6 nameof
void Foo(string par) {
if (par == null) throw new ArgumentNullException(nameof(par));
}
En el primer caso, si refactoriza el método que cambia el nombre del parámetro par , probablemente se olvide de cambiar eso en ArgumentNullException . Con nameof no tienes que preocuparte por eso.
Vea también: nameof (C # y Referencia de Visual Basic)
Es realmente útil para
ArgumentException
y sus derivados:
public string DoSomething(string input)
{
if(input == null)
{
throw new ArgumentNullException(nameof(input));
}
...
Ahora, si alguien refactoriza el nombre del parámetro de
input
, la excepción también se mantendrá actualizada.
También es útil en algunos lugares donde previamente se tuvo que usar la reflexión para obtener los nombres de propiedades o parámetros.
En su ejemplo,
nameof(T)
obtiene el nombre del parámetro de tipo; esto también puede ser útil:
throw new ArgumentException(nameof(T), $"Type {typeof(T)} does not support this method.");
Otro uso de
nameof
es para las enumeraciones, generalmente si desea el nombre de cadena de una enumeración que utiliza
.ToString()
:
enum MyEnum { ... FooBar = 7 ... }
Console.WriteLine(MyEnum.FooBar.ToString());
> "FooBar"
En realidad, esto es relativamente lento ya que .Net mantiene el valor de enumeración (es decir,
7
) y encuentra el nombre en tiempo de ejecución.
En su lugar, use
nameof
:
Console.WriteLine(nameof(MyEnum.FooBar))
> "FooBar"
Ahora .Net reemplaza el nombre de enumeración con una cadena en tiempo de compilación.
Sin embargo, otro uso es para cosas como
INotifyPropertyChanged
y el registro; en ambos casos, desea que el nombre del miembro que está llamando se pase a otro método:
// Property with notify of change
public int Foo
{
get { return this.foo; }
set
{
this.foo = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.Foo));
}
}
O...
// Write a log, audit or trace for the method called
void DoSomething(... params ...)
{
Log(nameof(DoSomething), "Message....");
}
Otro caso de uso de
nameof
es verificar las páginas de pestañas, en lugar de verificar el índice, puede verificar la propiedad
Name
de las pestañas de la siguiente manera:
if(tabControl.SelectedTab.Name == nameof(tabSettings))
{
// Do something
}
Menos desordenado :)
Su pregunta ya expresa el propósito. Debe ver que esto puede ser útil para iniciar sesión o lanzar excepciones.
por ejemplo.
public void DoStuff(object input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
}
Esto es bueno, si cambio el nombre de la variable, el código se romperá o devolverá una excepción con un mensaje incorrecto .
Por supuesto, los usos no se limitan a esta simple situación.
Puede usar
nameof
siempre que sea útil codificar el nombre de una variable o propiedad.
Los usos son múltiples cuando considera varias situaciones vinculantes y de reflexión. Es una excelente manera de llevar los errores de tiempo de ejecución al tiempo de compilación.
Tenga en cuenta que usa una variable en su código y necesita obtener el nombre de la variable y digamos imprimirla, debe usar
int myVar = 10;
print("myVar" + " value is " + myVar.toString());
Y si alguien refactoriza el código y usa otro nombre para "myVar", él / ella tendría que estar atento al valor de la cadena en su código y cambiarlo en consecuencia.
En cambio si tuvieras
print(nameof(myVar) + " value is " + myVar.toString());
¡Sería útil refactorizar automáticamente!
Tiene ventaja cuando usa ASP.Net MVC. Cuando utiliza el ayudante HTML para generar algún control a la vista, utiliza nombres de propiedad en la atribución de nombre de la entrada html:
@Html.TextBoxFor(m => m.CanBeRenamed)
Hace algo así:
<input type="text" name="CanBeRenamed" />
Entonces, si necesita validar su propiedad en el método Validar, puede hacer esto:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
if (IsNotValid(CanBeRenamed)) {
yield return new ValidationResult(
$"Property {nameof(CanBeRenamed)} is not valid",
new [] { $"{nameof(CanBeRenamed)}" })
}
}
En caso de que cambie el nombre de su propiedad utilizando herramientas de refactorización, su validación no se interrumpirá.
Uno de los usos de la palabra clave
nameof
es establecer
Binding
en wpf mediante
programación
.
Para establecer el
Binding
, debe establecer la
Path
con una cadena, y con el
nameof
palabra clave, es posible usar la opción Refactor.
Por ejemplo, si tiene la propiedad de dependencia
IsEnable
en su
UserControl
y desea vincularla a
IsEnable
de algún
CheckBox
en su
UserControl
, puede usar estos dos códigos:
CheckBox chk = new CheckBox();
Binding bnd = new Binding ("IsEnable") { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);
y
CheckBox chk = new CheckBox();
Binding bnd = new Binding (nameof (IsEnable)) { Source = this };
chk.SetBinding(IsEnabledProperty, bnd);
Es obvio que el primer código no puede refactorizar, pero el primero ...
Otro caso de uso en el que el
nameof
función de C # 6.0 se vuelve útil
: considere una biblioteca como
Dapper
que hace que las recuperaciones de DB sean mucho más fáciles.
Aunque esta es una gran biblioteca, necesita codificar los nombres de propiedad / campo dentro de la consulta.
Lo que esto significa es que si decide cambiar el nombre de su propiedad / campo, hay muchas posibilidades de que se olvide de actualizar la consulta para usar nuevos nombres de campo.
Con la interpolación de cadenas y el
nameof
características, el código se vuelve mucho más fácil de mantener y seguro.
Del ejemplo dado en el enlace
sin nombre de
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
con nombre de
var dog = connection.Query<Dog>($"select {nameof(Dog.Age)} = @Age, {nameof(Dog.Id)} = @Id", new { Age = (int?)null, Id = guid });
El artículo de MSDN enumera el enrutamiento MVC (el ejemplo que realmente hizo clic en el concepto para mí) entre varios otros. El párrafo de descripción (formateado) dice:
- Al informar errores en el código,
- conectar enlaces modelo-vista-controlador (MVC),
- disparando propiedad cambió eventos, etc.,
a menudo desea capturar el nombre de cadena de un método . Usar nameof ayuda a mantener su código válido al cambiar el nombre de las definiciones.
Antes tenía que usar literales de cadena para referirse a las definiciones, lo cual es frágil al renombrar elementos de código porque las herramientas no saben verificar estos literales de cadena.
Las respuestas aceptadas / mejor valoradas ya dan varios ejemplos concretos excelentes.