two - string to int 32 c#
¿Cómo int+string se convierte en string? (9)
Concatenación de cuerdas:
… string operator +(object x, string y);
El operador binario
+
realiza la concatenación de cadenas cuando uno o ambos operandos son de tipo cadena. Si un operando de concatenación de cadenas es nulo, se sustituye una cadena vacía. De lo contrario, cualquier operando que no sea una cadena se convierte a su representación de cadena invocando el método virtualToString
heredado delobject
tipo. SiToString
devuelve unnull
, se sustituye una cadena vacía. - ECMA-334 , página 201.
Por lo tanto, se llama n.ToString()
. Todo lo demás en el método es simplemente descomponer y recomponer el resultado sin ningún efecto.
Podría haber sido escrito como:
public string tostr(int n) => n.ToString();
¿Pero por qué?
Encontré una forma extraña de implementar ToString()
y me pregunto cómo funciona:
public string tostr(int n)
{
string s = "";
foreach (char c in n-- + "") { //<------HOW IS THIS POSSIBLE ?
s = s + c;
}
return s;
}
¿El iterador está asumiendo el tamaño de un char
?
Como n--
es un decremento posterior, el valor de n solo se cambia después de la concatenación. tan esencialmente no está haciendo nada en absoluto. podría haber sido simplemente
foreach (char c in n + "")
o
foreach (char c in (n++) + "")
de cualquier manera nada cambia. el valor original se itera
El tipo de n--
es int
, que se convierte en string
utilizando +
para concatenarla con ""
, que es de tipo string
. Además, la string
implementa IEnumerable<char>
, sobre la cual tiene lugar la iteración real con foreach
.
Este código parece incomprensible porque es el resultado de lo que considero una elección de diseño horrible en el idioma.
El operador +
no existe realmente en la string
. Si observa la fuente de referencia o la página de MSDN , los únicos operadores declarados para la string
son ==
y !=
.
Lo que realmente sucede es que el compilador extrae uno de sus trucos mágicos y convierte al operador +
en una llamada al método estático string.Concat
.
Ahora, si se encuentra con foreach (char c in string.Concat(n--, ""))
probablemente entendería el código mucho mejor, porque la intención es clara : quiero concatenar dos objetos como cadenas y luego enumerar los caracteres que componen la cadena resultante.
Cuando lees n-- + ""
esa intención está lejos de ser clara, y es peor si tienes n-- + s
( s
es una string
).
El compilador en ambos casos decide que desea concatenar los argumentos como cadenas y automáticamente asigna esta llamada a string.Concat(object, object)
. Uno de los inquilinos de C # es que, a menos que la intención del programador sea clara, ondea una bandera roja y le pide al programador que aclare su intención. En este caso particular, ese inquilino es violado completamente.
En mi humilde opinión, cualquier cosa que no sea una string + string
debería haber sido un error de compilación, pero ese tren pasó hace muchos años.
Explicando esto "paso a paso":
// assume the input is 1337
public string tostr(int n) {
//line below is creating a placeholder for the result string
string s = "";
// below line we can split into 2 lines to explain in more detail:
// foreach (char c in n-- + "") {
// then value of n is concatenated with an empty string :
// string numberString = n-- + ""; // numberString is "1337";
// and after this line value of n will be 1336
// which then is iterated though :
// foreach(char c in numberString) { // meaning foreach(char c in "1337")
foreach (char c in n-- + "") { //<------HOW IS THIS POSSIBLE ?
s = s + c; // here each sign of the numberString is added into the placeholder
}
return s; // return filled placeholder
}
Básicamente, si concatena una string
con int
, llamará automáticamente int.ToString
método int.ToString
y unirá la cadena.
He usado ReSharper para convertir la función en sentencias de Linq que pueden ayudar a algunas personas a entender lo que está pasando (o simplemente confundir a la gente aún más).
public string tostrLinq(int n)
{
return string.Concat(n--, "").Aggregate("", (string current, char c) => current + c);
}
Como ya han dicho otros, básicamente el int
introducido se concuerda con una string
vacía que básicamente le da una representación de la cadena del int
. A medida que la string
implementa IEnumberable
, el bucle foreach
divide la cadena en un char[]
, dando cada carácter de la cadena en cada iteración. El cuerpo del bucle justo entonces une a los personajes nuevamente como una cadena a través de la concatenación de cada char
.
Entonces, por ejemplo, dada la entrada de 5423
, se convierte a "5423"
, y luego se divide en "5"
, "4"
, "2"
, "3"
y finalmente se vuelve a "5423"
a "5423"
.
Ahora, la parte que realmente me lastimó la cabeza durante un tiempo fue la n--
. Si esto disminuye la int
, entonces ¿por qué no "5422"
? Esto no me quedó claro hasta después de que leí el artículo de MSDN: Operadores de incremento (++) y disminución (-)
Los operadores de incremento y decremento se utilizan como acceso directo para modificar el valor almacenado en una variable y acceder a ese valor. Cualquiera de los operadores puede usarse en una sintaxis de prefijo o postfijo.
If | Equivalent Action | Return value ===================================== ++variable | variable += 1 | value of variable after incrementing variable++ | variable += 1 | value of variable before incrementing --variable | variable -= 1 | value of variable after decrementing variable-- | variable -= 1 | value of variable before decrementing
Entonces, dado que el operador de disminución se aplica al final a n
, el valor de n
es leído y utilizado por string.Concat
antes de que n
disminuya en 1.
Es decir, string.Concat(n--,"")
dará la misma salida que string.Contact(n, ""); n = n - 1;
string.Contact(n, ""); n = n - 1;
.
Entonces, para obtener "5422"
, lo cambiaríamos a string.Concat(--n, "")
para que n
disminuya primero antes de pasarlo a string.Contact
.
TL; DR; La función es una forma redonda de hacer n.ToString()
Curiosamente, también usé ReSharper para convertirlo en un bucle for
pero la función ya no funciona a medida que n
disminuye en cada iteración del bucle for, a diferencia del bucle foreach
:
public string tostrFor(int n)
{
string s = "";
for (int index = 0; index < string.Concat(n--, "").Length; index++)
{
char c = string.Concat(n--, "")[index];
s = s + c;
}
return s;
}
Llama al String.Concat(object, object)
implícitamente, que concatena las representaciones de cadena de dos objetos especificados:
string result = String.Concat("", n--);
El String.Concat(object, object)
luego llama a String.Concat(string, string)
. Para leer la fuente de Concat
y verificarla en profundidad, primero vaya aquí: String.cs código fuente en C # .NET y luego en esa página en la búsqueda Tipo de String
TextBox
y luego haga clic en el enlace String.cs
en los resultados para Vaya al código fuente de String.cs en la página C # .NET y verifique el método Concat
.
Esta es la definición del método:
public static String Concat(Object arg0, Object arg1)
{
Contract.Ensures(Contract.Result<string>() != null);
Contract.EndContractBlock();
if (arg0 == null)
{
arg0 = String.Empty;
}
if (arg1==null)
{
arg1 = String.Empty;
}
return Concat(arg0.ToString(), arg1.ToString());
}
Como ves, esto llama finalmente al método public static String Concat(String str0, String str1)
:
public static String Concat(String str0, String str1)
{
Contract.Ensures(Contract.Result<string>() != null);
Contract.Ensures(Contract.Result<string>().Length ==
(str0 == null ? 0 : str0.Length) +
(str1 == null ? 0 : str1.Length));
Contract.EndContractBlock();
if (IsNullOrEmpty(str0)) {
if (IsNullOrEmpty(str1)) {
return String.Empty;
}
return str1;
}
if (IsNullOrEmpty(str1)) {
return str0;
}
int str0Length = str0.Length;
String result = FastAllocateString(str0Length + str1.Length);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0Length, str1);
return result;
}
Y esta es la IL subyacente, por Ildasm :
.method public hidebysig instance string
tostr(int32 n) cil managed
{
// Code size 74 (0x4a)
.maxstack 3
.locals init ([0] string s,
[1] string V_1,
[2] int32 V_2,
[3] char c,
[4] string V_4)
IL_0000: nop
IL_0001: ldstr ""
IL_0006: stloc.0
IL_0007: nop
IL_0008: ldarg.1
IL_0009: dup
IL_000a: ldc.i4.1
IL_000b: sub
IL_000c: starg.s n
IL_000e: box [mscorlib]System.Int32
IL_0013: call string [mscorlib]System.String::Concat(object)
IL_0018: stloc.1
IL_0019: ldc.i4.0
IL_001a: stloc.2
IL_001b: br.s IL_0039
IL_001d: ldloc.1
IL_001e: ldloc.2
IL_001f: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_0024: stloc.3
IL_0025: nop
IL_0026: ldloc.0
IL_0027: ldloca.s c
IL_0029: call instance string [mscorlib]System.Char::ToString()
IL_002e: call string [mscorlib]System.String::Concat(string,
string)
IL_0033: stloc.0
IL_0034: nop
IL_0035: ldloc.2
IL_0036: ldc.i4.1
IL_0037: add
IL_0038: stloc.2
IL_0039: ldloc.2
IL_003a: ldloc.1
IL_003b: callvirt instance int32 [mscorlib]System.String::get_Length()
IL_0040: blt.s IL_001d
IL_0042: ldloc.0
IL_0043: stloc.s V_4
IL_0045: br.s IL_0047
IL_0047: ldloc.s V_4
IL_0049: ret
}// end of method tostr
Para desglosar tu código para mostrar por qué sucede ...
foreach(char c in n-- + "")
el uso del operador +
con una cadena como uno de los operandos convertirá el resultado en una cadena independientemente de lo que fue el otro operando primitivo, siempre que tuviera una implementación de +. Al hacerlo, n participa en el método string.Concat
como se puede ver en la siguiente captura de pantalla de la ventana de depuración de Autos ...
Llamé al método con "34" como puedes inferir. El identificador de bucle allí se define como char c
y pasa por una cadena. Esto funciona porque la string
implementa IEnumerable<char>
como se puede ver en la captura de pantalla del resultado de "Ir a la definición" del tipo de cadena:
Entonces, desde ese punto, funciona igual que si estuvieras iterando a través de cualquier otra lista / conjunto ... o más exactamente, IEnumerable con foreach
y obtiene cada char
individual. n
en el tiempo medio se ha cambiado a n-- // 33 in my case
. En este punto, el valor de n
es intrascendente ya que está iterando a través del resultado de la expresión n-- + ""
. Puede que haya sido n++
y obtendrías el mismo resultado.
La línea s = s + c;
debe explicarse por sí mismo y, en caso de que no lo sea, cada carácter que extraiga del resultado de la cadena temporal de n-- + ""
se adjunta a su string s = "";
vacía (al principio) string s = "";
. Resulta en una cadena porque como se mencionó anteriormente +
con una cadena involucrada resultará en una cadena. Una vez que haya terminado de pasar por todos los caracteres, devuelve la representación de cadena.
n-- + ""
es lo mismo que
n + ""
porque no usamos el valor de n más tarde
n + ""
es lo mismo que
n.ToString()
porque el operador + se usa con int y string convierte int a string, entonces
foreach (char c in n-- + "")
es lo mismo que
foreach (char c in n.ToString())
el resto es simple