c# - error - Diferencia entre nameof y typeof
nameof c# error (7)
Aquí hay una prueba de referencia utilizando BenchmarkDotNet
// * Summary *
Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Windows
Processor=?, ProcessorCount=8
Frequency=2740584 ticks, Resolution=364.8857 ns, Timer=TSC
CLR=CORE, Arch=64-bit ? [RyuJIT]
GC=Concurrent Workstation
dotnet cli version: 1.0.0-preview2-003133
Type=GetNameBenchmark Mode=Throughput LaunchCount=2
WarmupCount=10 TargetCount=200
Method | Median | StdDev |
----------- |----------- |---------- |
TypeOf | 16.0348 ns | 0.7896 ns |
NameOf | 0.0005 ns | 0.0147 ns |
Corrígeme si me equivoco, pero haciendo algo como
var typeOfName = typeof(Foo).Name;
y
var nameOfName = nameof(Foo);
debe darle exactamente la misma salida. Una de las razones comprensibles de acuerdo a esta fuente: https://msdn.microsoft.com/en-us/library/dn986596.aspx es que
"Usar nameof ayuda a mantener su código válido al cambiar el nombre de las definiciones"
Si desea obtener la instancia de clase como una cadena, no es posible hacer algo así:
var fooInstance = new Foo();
var nameOfName = nameof(fooInstance);
Sin embargo, puedes hacer algo como:
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
var typeOfName2 = GetName(new { fooInstance });
En ambos casos ( typeof
y nameof
) es posible una refactorización, por lo que no veo ninguna otra razón para reinventar otra palabra clave de nivel superior, como nameof
, para realizar algo que ya existe. ¿Hay alguna diferencia entre ellos que no veo claramente?
Finalmente, agradecería que alguien me nameof
una fuente de referencia para echar un vistazo a la implementación de nameof
. ¿Utiliza la reflexión?
Actualización 1: Tomado de here
nameof
es aparentemente tan eficiente como declarar una variable de cadena. ¡No hay reflexión ni nada!
var firstname = "Gigi";
var varname = nameof(firstname);
Console.WriteLine(varname); // Prints "firstname" to the console
Cuando revise la MSIL generada, verá que es equivalente a una declaración de cadena porque una referencia de objeto a una cadena se inserta en la pila utilizando el operador ldstr:
IL_0001: ldstr "Gigi"
IL_0006: stloc.0
IL_0007: ldstr "firstname"
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: call void [mscorlib]System.Console::WriteLine(string)
Dos razones:
nameof
convierte en una constante de compilación. typeof(...).Name
requiere un poco de reflexión. No es demasiado caro, pero puede doler en algunos casos.
En segundo lugar, se utiliza para otras cosas que los nombres de tipo. Por ejemplo, argumentos:
void SomeMethod(int myArgument)
{
Debug.WriteLine(nameof(myArgument));
}
También puede obtener el nombre de los miembros de la clase e incluso de los locales. No hace falta decir que esto es bastante útil para depurar información. También es una de las formas de implementar una reflexión menos frágil cuando, por ejemplo, analizando árboles de expresiones (lamentablemente, en el proyecto en el que usaría esto, todavía estamos atrapados en .NET 4.0 con C # 5; me ahorraría algunos trucos). aquí y allá).
Y para aclarar algunas confusiones, nameof
no es una función, y tampoco lo es typeof
. Es un operador en tiempo de compilación, y siempre se evalúa en tiempo de compilación (aunque obviamente, los genéricos mueven el "tiempo de compilación" un poco más en el tiempo).
Existen varias diferencias entre ellos, pero se deben principalmente a razones prácticas. Ejemplo 1:
Es más elegante escribir algo como
switch (e.ArgumentPropertyName)
{
case nameof(aProperty):
break;
case "anotherProperty":
break;
}
Trate de refactorizar anotherProperty
tipo de anotherProperty
y bang! el nameof
reflejará los cambios, la "anotherProperty"
pasará en silencio y su código nunca se ejecutará dentro de esa declaración de caso.
Ejemplo 2:
enum MetalEnum { Gold = 1, Silver = 2, ... }
¿Cuál es mejor?
Console.WriteLine(MetalEnum.Gold.ToString()); // finds the name at runtime (slower)
o
Console.WriteLine(nameof(MetalEnum.Gold)); // compile time (faster)
Ejemplo 3:
Finalmente, ¿recuerdas lo feo que es escribir algo como
PropertyChanged(this, new PropertyChangedEventArgs("Foo"));
Ahora puedes escribir tan bellamente como sigue:
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Foo)));
Según la documentación :
Se usa para obtener el nombre de cadena simple (no calificado) de una variable, tipo o miembro.
...
El argumento a nombre de debe ser un nombre simple, un nombre calificado, acceso de miembro, acceso base con un miembro específico o este acceso con un miembro específico. La expresión de argumento identifica una definición de código, pero nunca se evalúa.
Debido a que el argumento debe ser una expresión sintáctica, hay muchas cosas que no están permitidas y que no son útiles enumerar. Vale la pena mencionar lo siguiente que produce errores: tipos predefinidos (por ejemplo, int o void ), tipos anulables (
Point?
), Tipos de matriz (Customer[,]
), tipos de puntero (Buffer*
), alias calificado (A::B
), y tipos genéricos no enlazados (Dictionary<,>
), símbolos de preprocesamiento (DEBUG
) y etiquetas (loop:
.
El nombre simple que obtiene nameof es el nombre de la fuente, no el nombre de los metadatos.
Por lo tanto, este código:
using Integer = System.Int32;
var s = "a string";
Console.WriteLine(nameof(s));
Console.WriteLine(nameof(Integer));
Console.WriteLine(nameof(System.Int32));
void M<T>() { Console.WriteLine(nameof(T)); }
M<int>();
M<string>();
imprimirá:
s
Integer
Int32
T
T
Typeof devuelve los objetos Type. A menudo se utiliza como un parámetro o como una variable o campo. El operador typeof es parte de una expresión que adquiere el puntero de tipo.
Nameof, mientras tanto, devuelve una cadena con el nombre de una variable. Funciona en tiempo de compilación. Es una característica especial del compilador que simplifica algunos programas.
Usar la reflexión para generar cadenas es posible, pero no es muy elegante y no siempre es posible. No se puede usar Reflexión en código de espacio aislado, por ejemplo. Y no puedes usarlo en variables locales. Y es caro.
El operador nameof
trabaja en tiempo de compilación. El compilador ya conoce el nombre cuando analiza el código. Así se puede generar trivialmente la cadena literal. Muy rápido, no puede ser más rápido y no hay restricciones de tiempo de ejecución.
Typeof devuelve los objetos Type. A menudo se utiliza como un parámetro o como una variable o campo. El operador typeof es parte de una expresión que adquiere el puntero de tipo.
class Program
{
static Type _type = typeof(char); // Store Type as field.
static void Main()
{
Console.WriteLine(_type); // Value type pointer
Console.WriteLine(typeof(int)); // Value type
Console.WriteLine(typeof(byte)); // Value type
Console.WriteLine(typeof(Stream)); // Class type
Console.WriteLine(typeof(TextWriter)); // Class type
Console.WriteLine(typeof(Array)); // Class type
Console.WriteLine(typeof(int[])); // Array reference type
}
}
Salida
System.Char
System.Int32
System.Byte
System.IO.Stream
System.IO.TextWriter
System.Array
System.Int32[]
Nameof , mientras tanto, devuelve una cadena con el nombre de una variable. Funciona en tiempo de compilación. Es una característica especial del compilador que simplifica algunos programas.
int size=100;
Console.WriteLine(nameof(size));
salida : tamaño