elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Como proteger una cartera - billetera de Bitcoin


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  Tiene que haber otra forma de hacer este código.
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] 2 Ir Abajo Respuesta Imprimir
Autor Tema: Tiene que haber otra forma de hacer este código.  (Leído 3,884 veces)
Meta


Desconectado Desconectado

Mensajes: 3.501



Ver Perfil WWW
Tiene que haber otra forma de hacer este código.
« en: 25 Julio 2024, 09:32 am »

Buenas:

Digamos que entro en una función y me lleva hasta aquí, en modo consola y C#.

Tengo este código.
Código
  1.            // Lee tecla hasta que detecte que haz pulsado Enter.
  2.            while (Console.ReadKey(true).Key != ConsoleKey.Enter)
  3. {
  4.  
  5. }

No hay nada dentro del While como puedes ver.

Si pulso la tecla Enter, vuelve de donde viene y sale de ahí.

Si pongo if(), solo se ejecuta una vez, se necesita que el teclado lo detecte al pulsarlo, la tecla Enter en este caso para salir de ese bucle.

¿Hay algo mejor que esto?

Saludos.


En línea

Tachikomaia


Desconectado Desconectado

Mensajes: 1.460


Hackentifiko!


Ver Perfil
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #1 en: 25 Julio 2024, 12:41 pm »

Suelo no entender tus dudas ¿quieres que se repita código hasta que se presione Enter? Pero no hay código, dices ¿entonces quieres que el programa se detenga hasta que se presione Enter?


En línea

Danielㅤ


Desconectado Desconectado

Mensajes: 1.853


🔵🔵🔵🔵🔵🔵🔵


Ver Perfil
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #2 en: 25 Julio 2024, 16:22 pm »

Hola, lo que entiendo que querés hacer con tu código, es que si se escribe cualquier tecla el programa simplemente siga su bucle sin mostrar nada en pantalla y que la consola siga abierta, pero si se pulsa Enter, entonces el programa se cierra, es así?.

Lo primero decirte que esa condición no es recomendable hacerla en un bucle, siempre es mejor hacerla dentro de un If y que la condición del bucle sea por ejemplo el 1, para que sea un bucle infinito:

Código
  1. while (1) {
  2.    If (Console.ReadKey(true).Key == ConsoleKey.Enter) { break; }
  3. }

Ahí dejé una forma parecida de hacer lo que deseas.


Saludos
« Última modificación: 26 Julio 2024, 02:53 am por Danielㅤ » En línea

Meta


Desconectado Desconectado

Mensajes: 3.501



Ver Perfil WWW
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #3 en: 25 Julio 2024, 17:38 pm »

Me funciona tal como les comenté en el primer post, en el último dice que no es recomendable.

¿Por qué no es recomendable exactamente?

¿Se puede bloquear el programa para todo al vida?

Código
  1.            while (true)
  2.            {
  3.                if (Console.ReadKey(true).Key == ConsoleKey.Enter) { break; }
  4.            }

Si me funciona de maravilla tu código. Muchísimas gracias por comentar.  ;-) ;-) ;-) ;-) ;-) ;-)
En línea

EdePC
Moderador Global
***
Desconectado Desconectado

Mensajes: 2.176



Ver Perfil
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #4 en: 26 Julio 2024, 01:00 am »

El While usa una condición, es decir,  ya tiene un "if" incluido, al menos yo no creo que haya problemas con eso.

Si lo que quieres es tal cual han entendido Daniel y Tachikomaia te debería bastar con:

Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter);

- Nótese que no lleva cuerpo ({...}) y directamente termina con ;
- Ese es el ejemplo que muestra la ayuda de mi viejo Visual Studio 2008

En la Ayuda actual https://learn.microsoft.com/es-es/dotnet/api/system.console.readkey?view=net-8.0 muestra como ejemplo:

Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter) {}

- De todas maneras también utiliza la forma que yo comenté un poquito más abajo, en otro ejemplo muestra:

Código
  1. do {
  2.  // ...
  3. } while (cki.Key != ConsoleKey.Escape);

Así que yo estimo que ambas formas están bien, yo me quedo con el ; al final en lugar de las dos llaves, porque siempre debe haber una u otra, sino interpretará como cuerpo del while la siguiente línea. Los siguientes ejemplo son válido y se usa cuando el cuerpo de la estructura (while, do while, for, if, etc) solo consta de una sola instrucción/línea:

Ejemplo 1:
Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter) Console.Write("No has tecleado Enter");
  2. Console.Write("Ya estás fuera del While");

- Lo anterior se ve bastante en if sencillos como si fuera el operador ternario, estas dos líneas hacen exactamente lo mismo:

Código
  1. if(x != 0.0) s = Math.Sin(x)/x; else s = 1.0;
  2.  
  3. s = x != 0.0 ? Math.Sin(x)/x : 1.0;

Ejemplo 2:
Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter)
  2.  Console.Write("No has tecleado Enter");
  3. Console.Write("Ya estás fuera del While");

- Lo anterior se ve bastante en for anidados como los típicos para aplicar fuerza bruta, recorrer arrays dentro de arrays,

Código
  1. public static void Main() {
  2.  
  3.  int tabla, numero;
  4.  
  5.  for (tabla = 1; tabla <= 5; tabla++)
  6.    for (numero = 1; numero <= 10; numero++)
  7.      Console.WriteLine("{0} por {1} es {2}", tabla, numero, tabla*numero);
  8. }
En línea

Meta


Desconectado Desconectado

Mensajes: 3.501



Ver Perfil WWW
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #5 en: 26 Julio 2024, 02:44 am »

Al final, ¿este código está bien?
Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter) { }

Porque dice arriba que no es recomendable. No dijo el motivo.
En línea

Danielㅤ


Desconectado Desconectado

Mensajes: 1.853


🔵🔵🔵🔵🔵🔵🔵


Ver Perfil
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #6 en: 26 Julio 2024, 02:59 am »

No es recomendable porque siempre el while va a depender de esa única acción, es decir que compare todos los ciclos/vueltas con lo de la tecla Enter y no tendrá otra condición que esa, siempre es mejor manejar los bucles de una manera más dinámica y no tan única como esa, por eso no es recomendable.

Lo que dice EdePC es correcto en cuánto él se refiere a no usar las llaves de apertura y cierre, si bien es así y el programa puede funcionar perfectamente, pero yo no recomiendo esa forma porque siempre que no se usen las llaves la instrucción tiene que ser una sola para funcionar, si se ingresan 2 o más instrucciones lo más probable es que de error, además es mejor legible el programa usando las llaves aunque sea para una sola instrucción porque en el futuro si se quisiera modificar el código para agregar más instrucciones, entonces las llaves ya estarán puestas.
Hasta donde yo recuerdo esto era así en C++ y seguramente también será igual en C#.

En cuánto a si se puede bloquear el programa para toda la vida, supongo que te referís a que si se escribe cualquier tecla incluso el Enter, el programa siga con la ventana abierta, si es posible, una forma es ésta:

Código
  1. while (1) {
  2.    If (Console.ReadKey(true).Key == ConsoleKey.Enter) { continue; }
  3. }

o mejor aún:

Código
  1. while (1) {
  2.    continue;
  3. }

Código
  1. while (1) {
  2.    If (true)
  3. }

Código
  1. while (true) {
  2.    continue;
  3. }
En línea

Meta


Desconectado Desconectado

Mensajes: 3.501



Ver Perfil WWW
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #7 en: 26 Julio 2024, 09:58 am »

Por como lo explica, lo dejo así tal cual en C#.
Código
  1.            // Lee tecla hasta que detecte que haz pulsado Enter.
  2.            while (true)
  3.            {
  4.                if (Console.ReadKey(true).Key == ConsoleKey.Enter) { break; }
  5.            }

Lo del while(1) en C# no funciona.
En línea

**Aincrad**


Desconectado Desconectado

Mensajes: 683



Ver Perfil WWW
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #8 en: 26 Julio 2024, 15:38 pm »

tambien podrias hacer una funcion booleana recursiva  ;) .

Código
  1.  
  2. // bool SelectMenu = Menu();
  3.  
  4.  private static bool Menu()
  5.    {
  6.        if (Console.ReadKey(true).Key == ConsoleKey.Enter)  {
  7.            return true;
  8.        }    else  {
  9.            return Menu();
  10.        }
  11.    }
  12.  
« Última modificación: 26 Julio 2024, 15:41 pm por **Aincrad** » En línea



EdePC
Moderador Global
***
Desconectado Desconectado

Mensajes: 2.176



Ver Perfil
Re: Tiene que haber otra forma de hacer este código.
« Respuesta #9 en: 26 Julio 2024, 16:20 pm »

Eres libre de usar la forma que veas por conveniente, pero a simple vista para tu caso sencillo donde quieres que no se salga del programa hasta que se presione Enter debería bastar con:

Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter);

Lo que dice Daniel es cierto cuando el  bucle es infinito por diseño: while(true), Así que ahí dependes del cuerpo del while para salir del bucle.

Si nos vamos a las entrañas de una aplicación en .net descompilándolo a IL tenemos:

Caso 1:
Código
  1. while (Console.ReadKey(true).Key != ConsoleKey.Enter);

Código
  1. .method private hidebysig static void  Main() cil managed
  2. {
  3.  .entrypoint
  4.  // Code size       29 (0x1d)
  5.  .maxstack  2
  6.  .locals init ([0] valuetype [mscorlib]System.ConsoleKeyInfo CS$0$0000,
  7.           [1] bool CS$4$0001)
  8.  IL_0000:  nop
  9.  IL_0001:  br.s       IL_0003
  10.  IL_0003:  ldc.i4.1
  11.  IL_0004:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
  12.  IL_0009:  stloc.0
  13.  IL_000a:  ldloca.s   CS$0$0000
  14.  IL_000c:  call       instance valuetype [mscorlib]System.ConsoleKey [mscorlib]System.ConsoleKeyInfo::get_Key()
  15.  IL_0011:  ldc.i4.s   13
  16.  IL_0013:  ceq
  17.  IL_0015:  ldc.i4.0
  18.  IL_0016:  ceq
  19.  IL_0018:  stloc.1
  20.  IL_0019:  ldloc.1
  21.  IL_001a:  brtrue.s   IL_0003
  22.  IL_001c:  ret
  23. } // end of method Program::Main

Caso 2:

Código
  1. while (true) {
  2.  if (Console.ReadKey(true).Key == ConsoleKey.Enter) { break; }
  3. }

Código
  1. .method private hidebysig static void  Main() cil managed
  2. {
  3.  .entrypoint
  4.  // Code size       38 (0x26)
  5.  .maxstack  2
  6.  .locals init ([0] valuetype [mscorlib]System.ConsoleKeyInfo CS$0$0000,
  7.           [1] bool CS$4$0001)
  8.  IL_0000:  nop
  9.  IL_0001:  br.s       IL_0021
  10.  IL_0003:  nop
  11.  IL_0004:  ldc.i4.1
  12.  IL_0005:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
  13.  IL_000a:  stloc.0
  14.  IL_000b:  ldloca.s   CS$0$0000
  15.  IL_000d:  call       instance valuetype [mscorlib]System.ConsoleKey [mscorlib]System.ConsoleKeyInfo::get_Key()
  16.  IL_0012:  ldc.i4.s   13
  17.  IL_0014:  ceq
  18.  IL_0016:  ldc.i4.0
  19.  IL_0017:  ceq
  20.  IL_0019:  stloc.1
  21.  IL_001a:  ldloc.1
  22.  IL_001b:  brtrue.s   IL_0020
  23.  IL_001d:  nop
  24.  IL_001e:  br.s       IL_0025
  25.  IL_0020:  nop
  26.  IL_0021:  ldc.i4.1
  27.  IL_0022:  stloc.1
  28.  IL_0023:  br.s       IL_0003
  29.  IL_0025:  ret
  30. } // end of method Program::Main
  31.  

- He resaltado la parte que es idéntica en ambos casos (los nop se ignoran porque no hacen nada (NOP = No Operation)), solo queda analizar que hace la parte no resaltada del segundo caso:

En la línea 21 del primer caso y 22 del segundo caso hacen el salto si la tecla presionada es Enter, es decir, eso debería de hacer que se salga del bucle

- En el primer caso salta a IL_0003 que es el inicio del bucle así que es muy sencillo entender que el bucle se volverá a ejecutar, si no salta, simplemente hace un RET para salir del bucle

- En el segundo caso salta a IL_0020 que es un NOP, este no hace nada, así que pasamos a la siguiente instrucción IL_0021,  IL_0022 y IL_0023 donde ponen en la memoria (stack) 1, luego recuperan ese 1, y finalmente saltan incondicionalmente (si o si porque no comprueban nada) a IL_003 que es el inicio del bucle.

-- Si la tecla no fue Enter ejecutamos IL_001d que nuevamente es un NOP así que pasamos a IL_001e el cual es un salto incondicional a IL_0025, ahora bien, en IL_0025 está el RET para salir del bucle

Conclusión: El caso 1 es exactamente igual al caso dos, el caso dos es lo mismo salvo que hace otras otras inútiles, como NOP, poner valores en el stack, recuperarlas pero no hace absolutamente nada con ellas, salta a otros sitios que tampoco hacen nada, es decir, solo tiene código extra de relleno.

Por cierto he utilizado ildasm.exe para abrir el .exe generado y obtener su código IL que es al final lo que interpreta .NET, en mi caso lo tengo en C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\ildasm.exe

Si todo lo anterior resulta un poquito complicado de entender se puede usar una herramienta más amigable para obtener el código IL que va a interpretar finalmente .NET, por ejemplo ILSpy: https://github.com/icsharpcode/ILSpy para mi siguiente ejemplo usaré una versión más viejita: https://github.com/icsharpcode/ILSpy/releases/download/v7.2.1/ILSpy_binaries_7.2.1.6856.zip que es compatible con .NET 4.7, las nuevas versiones requieren .NET 8

Los siguientes casos son como interpreta ILSpy el .exe generado, para estos casos obviare el IL puro porque ya lo expliqué antes, solo me centraré a la decompilación C# que obtiene ILSpy:

Caso 1 por ILSpy:

Código
  1. // cprb.Program
  2. using System;
  3.  
  4. private static void Main()
  5. {
  6. while (Console.ReadKey(intercept: true).Key != ConsoleKey.Enter)
  7. {
  8. }
  9. }
  10.  

Caso 2 por ILSpy:

Código
  1. // cprb.Program
  2. using System;
  3.  
  4. private static void Main()
  5. {
  6. do
  7. {
  8. bool flag = true;
  9. }
  10. while (Console.ReadKey(intercept: true).Key != ConsoleKey.Enter);
  11. }
  12.  

- Bueno, es obvio que el primer caso se parece más al ejemplo que entrega Microsoft con las {} al final, aunque el código original del caso uno no los tiene y en su lugar le puse ;

- El segundo caso, se interpreta como un do while, PERO el cuerpo de este no hace nada, es decir, crea una variable flag que pone a true pero no hace nada con ella, luego está la condicional del do while que es exáctamente igual al Caso 1.

---
Como extra también pongo las instrucciones finales C# interpretado y IL para el aporte que acaba de por Aincrad:

Original:

Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace cprb {
  7.  class Program {
  8.    static void Main() {
  9.      Menu();
  10.    }
  11.  
  12.    private static bool Menu() {
  13.      if (Console.ReadKey(true).Key == ConsoleKey.Enter) {
  14.        return true;
  15.      } else {
  16.        return Menu();
  17.      }
  18.    }
  19.  
  20.  }
  21. }
  22.  

Interpretación C# por ILSpy:

Código
  1. using System;
  2.  
  3. internal class Program
  4. {
  5. private static void Main()
  6. {
  7. Menu();
  8. }
  9.  
  10. private static bool Menu()
  11. {
  12. if (Console.ReadKey(intercept: true).Key == ConsoleKey.Enter)
  13. {
  14. return true;
  15. }
  16. return Menu();
  17. }
  18. }
  19.  

Decompilación IL por ILSpy:

Código
  1. .class private auto ansi beforefieldinit cprb.Program
  2. extends [mscorlib]System.Object
  3. {
  4. // Methods
  5. .method private hidebysig static
  6. void Main () cil managed
  7. {
  8. // Method begins at RVA 0x2050
  9. // Header size: 1
  10. // Code size: 8 (0x8)
  11. .maxstack 8
  12. .entrypoint
  13.  
  14. IL_0000: nop
  15. IL_0001: call bool cprb.Program::Menu()
  16. IL_0006: pop
  17. IL_0007: ret
  18. } // end of method Program::Main
  19.  
  20. .method private hidebysig static
  21. bool Menu () cil managed
  22. {
  23. // Method begins at RVA 0x205c
  24. // Header size: 12
  25. // Code size: 42 (0x2a)
  26. .maxstack 2
  27. .locals init (
  28. [0] bool,
  29. [1] valuetype [mscorlib]System.ConsoleKeyInfo,
  30. [2] bool
  31. )
  32.  
  33. IL_0000: nop
  34. IL_0001: ldc.i4.1
  35. IL_0002: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey(bool)
  36. IL_0007: stloc.1
  37. IL_0008: ldloca.s 1
  38. IL_000a: call instance valuetype [mscorlib]System.ConsoleKey [mscorlib]System.ConsoleKeyInfo::get_Key()
  39. IL_000f: ldc.i4.s 13
  40. IL_0011: ceq
  41. IL_0013: ldc.i4.0
  42. IL_0014: ceq
  43. IL_0016: stloc.2
  44. IL_0017: ldloc.2
  45. IL_0018: brtrue.s IL_001f
  46.  
  47. IL_001a: nop
  48. IL_001b: ldc.i4.1
  49. IL_001c: stloc.0
  50. IL_001d: br.s IL_0028
  51.  
  52. IL_001f: nop
  53. IL_0020: call bool cprb.Program::Menu()
  54. IL_0025: stloc.0
  55. IL_0026: br.s IL_0028
  56.  
  57. IL_0028: ldloc.0
  58. IL_0029: ret
  59. } // end of method Program::Menu
  60.  
  61. .method public hidebysig specialname rtspecialname
  62. instance void .ctor () cil managed
  63. {
  64. // Method begins at RVA 0x2092
  65. // Header size: 1
  66. // Code size: 7 (0x7)
  67. .maxstack 8
  68.  
  69. IL_0000: ldarg.0
  70. IL_0001: call instance void [mscorlib]System.Object::.ctor()
  71. IL_0006: ret
  72. } // end of method Program::.ctor
  73.  
  74. } // end of class cprb.Program

---
Una vez Tachikomaia preguntó sobre la optimización de su código o porque no le funcionaban bien algunas instrucciones que requieren redondeo, en su caso el usa Flash 5 y yo comenté que podría usar JPEXS Free Flash Decompiler https://github.com/jindrapetrik/jpexs-decompiler para obtener el código final interpretado y el P-Code de sus .swf, esto es lo mismo que usar ILSpy para los .exe de .NET, con estos programas se puede ver que es lo que se ejecuta finalmente
« Última modificación: 27 Julio 2024, 00:02 am por EdePC » En línea

Páginas: [1] 2 Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
[MYSQL] Otra forma de hacer esta consulta?
Bases de Datos
klaine 1 3,476 Último mensaje 12 Noviembre 2011, 15:07 pm
por fran800m
Que errir tiene este codigo?
Java
Grey_Area 1 1,895 Último mensaje 29 Noviembre 2011, 22:40 pm
por Leyer
[AYUDA] ¿Qué tiene de malo este código?
Programación C/C++
Zodiak98 3 2,269 Último mensaje 26 Septiembre 2016, 22:16 pm
por Zodiak98
Que tiene mal este codigo?
Programación C/C++
Mozzard 2 2,108 Último mensaje 22 Septiembre 2018, 15:47 pm
por Mozzard
Que error tiene este codigo?
Programación C/C++
Mozzard 3 2,372 Último mensaje 2 Octubre 2018, 17:25 pm
por Beginner Web
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines