¿Cuál es el propósito de nameof?


La versión 6.0 tiene una nueva característica de nameof, pero no puedo entender el propósito de la misma, ya que solo toma el nombre de la variable y la cambia a una cadena en la compilación.

Pensé que podría tener algún propósito al usar <T> pero cuando intento nameof(T) simplemente me imprime un T en lugar del tipo utilizado.

¿Alguna idea sobre el propósito?

Author: Patrick Hofman, 2015-07-29

14 answers

¿Qué pasa con los casos en los que desea reutilizar el nombre de una propiedad, por ejemplo, al lanzar una excepción basada en un nombre de propiedad, o el manejo de un evento PropertyChanged. Hay numerosos casos en los que le gustaría tener el nombre de la propiedad.

Tomemos este ejemplo:

switch (e.PropertyName)
{
    case nameof(SomeProperty):
    { break; }

    // opposed to
    case "SomeOtherProperty":
    { break; }
}

En el primer caso, renombrar SomeProperty también cambiará el nombre de la propiedad, o romperá la compilación. El último caso no.

Esta es una forma 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 hizo, mientras que nameof lo hizo)

 245
Author: Patrick Hofman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-09 14:28:54

Es realmente útil para ArgumentException y sus derivados:

public string DoSomething(string input) 
{
    if(input == null) 
    {
        throw new ArgumentNullException(nameof(input));
    }
    ...

Ahora, si alguien refacciona el nombre del parámetro input, la excepción también se mantendrá actualizada.

También es útil en algunos lugares donde anteriormente se tenía que utilizar la reflexión para obtener los nombres de propiedades o parámetros.

En su ejemplo nameof(T) obtiene el nombre del parámetro type - 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 enumeraciones, generalmente si desea nombre de cadena de una enumeración que utilice .ToString():

enum MyEnum { ... FooBar = 7 ... }

Console.WriteLine(MyEnum.FooBar.ToString());

> "FooBar"

Esto es relativamente lento ya que.Net contiene 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 la enumeración con una cadena en tiempo de compilación.


Otro uso es para cosas como INotifyPropertyChanged y el registro : en ambos casos, desea que el nombre del miembro al 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....");
}
 140
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-31 07:52:08

Su pregunta ya expresa el propósito. Debe ver que esto podría ser útil para registrar 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á en su lugar 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 se consideran varias situaciones de unión y reflexión. Es una excelente manera de traer lo que fueron errores de tiempo de ejecución para compilar el tiempo.

 17
Author: Jodrell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-10 13:31:20

Otro caso de uso donde nameof la característica de C# 6.0 se vuelve útil - Considere una biblioteca como Dapper que hace que las recuperaciones de bases de datos sean mucho más fáciles. Aunque esta es una gran biblioteca, necesita codificar los nombres de propiedades / campos dentro de query. Lo que esto significa es que si decide cambiar el nombre de su propiedad/campo, hay altas posibilidades de que se olvide de actualizar la consulta para usar nuevos nombres de campo. Con la interpolación de cadenas y las características nameof, 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 });

 15
Author: 5a7335h,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-31 02:12:09

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 bindings utiliza esta interfaz)

Echa un vistazo a este 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 antigua, 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 imagine lo que sucede cuando alguien cambia el nombre de la propiedad Foo. Cuando se utiliza un string el enlace dejará de funcionar, pero el compilador no le avisará. Al usar nameof se obtiene un error del compilador que indica que no hay ninguna propiedad/argumento con el nombre Foo.

Tenga en cuenta que algunos frameworks usan alguna magia de reflexión para obtener el nombre de la propiedad, pero ahora tenemos nameof esto ya no es necesario.

 12
Author: Roy T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-24 22:33:44

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 cambiando el nombre del parámetro par, probablemente olvidará cambiarlo en la ArgumentNullException. Con nameof no tienes que preocuparte por eso.

Véase también: nameof (C# y Referencia Visual Basic)

 7
Author: Massimo Prota,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-29 09:09:45

El ASP.NET Core MVC project utiliza nameof en el AccountController.cs y ManageController.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 como:

return RedirectToAction("Index", "Home");

And takes lleva al usuario a la acción 'Index' en el controlador 'Home', es decir, /Home/Index.

 6
Author: Fred,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-04 22:38:55

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, usé un método estático que utilizaba la reflexión para el mismo propósito, pero que tiene un impacto en el rendimiento en tiempo de ejecución. El operador nameof no tiene impacto en el rendimiento en tiempo de ejecución; hace su trabajo en tiempo de compilación. Si echas un vistazo a el código MSIL encontrará la cadena incrustada. Vea el siguiente método y su código desensamblado.

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 puede no coincidir con el nombre del elemento. Los mecanismos que se basan en este texto se romperán. Ejemplos de esto, incluyendo pero no limitado a: Reflexión, NotifyPropertyChanged ...

Determinar el nombre durante el tiempo de ejecución cuesta algo de rendimiento, pero es seguro para ofuscación. Si la ofuscación no es necesaria ni planificada, recomendaría usar el operador nameof.

 6
Author: cel sharp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-27 19:45:39

Considere que usa una variable en su código y necesita obtener el nombre de la variable y digamos imprimirla, debería usar

int myVar = 10;
print("myVar" + " value is " + myVar.toString());

Y si entonces alguien refacciona el código y usa otro nombre para "myVar", tendría que buscar el valor de cadena en su código y chengarlo en consecuencia.

En lugar de eso, si tuvieras

print(nameof(myVar) + " value is " + myVar.toString());

¡Ayudaría refactorizar automáticamente!

 5
Author: cnom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-29 09:16:38

El artículo de MSDN lista 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 de errores en el código,
  • conexión de enlaces modelo-vista-controlador (MVC),
  • propiedad de disparo eventos cambiados, etc.,

A menudo quieres captura el nombre de cadena de un método. Usando nameof ayuda a mantener su codificar válido al cambiar el nombre de las definiciones.

Antes tenías que usar literales de cadena para referirse a las definiciones, que es frágil al cambiar el nombre de los elementos de código porque las herramientas no saben comprobar estos literales de cadena.

Las respuestas aceptadas / mejor valoradas ya dan varios ejemplos concretos excelentes.

 4
Author: brichins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-05 16:16:54

El propósito del operador nameof es proporcionar el nombre de origen de los artefactos.

Por lo general, el nombre de la fuente es el mismo nombre que el nombre de los 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 no siempre puede ser 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 comprobar que los recursos existir.

 3
Author: Paulo Morgado,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-04 11:13:01

Uno de los usos de la palabra clave nameof es para establecer Binding en wpf mediante programación.

Para establecer Binding tienes que establecer Path con cadena, y con la palabra clave nameof, es posible usar la opción Refactor.

Por ejemplo, si usted tiene IsEnable propiedad de dependencia en su UserControl y desea enlazar a IsEnable de algunos CheckBox en el UserControl, puede utilizar 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 secend una...

 0
Author: Mehdi Khademloo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-17 23:58:18

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)
{
    ...
}

Reason - seguridad en tiempo de compilación. Nadie puede cambiar el nombre de la propiedad en silencio y romper la lógica del código. Ahora podemos usar nameof ().

 0
Author: QtRoS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-26 22:09:14

Tiene ventaja cuando se utiliza ASP.Net MVC. Cuando se utiliza HTML helper para construir algún control en view, utiliza nombres de propiedad en la atribución de nombres de entrada html:

@Html.TextBoxFor(m => m.CanBeRenamed)

Hace algo así:

<input type="text" name="CanBeRenamed" />

Así que ahora, si necesita validar su propiedad en el método Validate, 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 romperá.

 0
Author: digizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-20 13:43:59