Alcance de las variables en C#


Tengo una pregunta para ustedes sobre la escritura de código en C# : Tuve un largo debate con un colega mío.: Dice que al declarar e inicializar todas las variables al principio de la función, el código es más legible y rápido.

Por favor dame al menos una razón cuerda de que podría ser correcto.

1. No es legible como si tuviera una función larga, tiene que tener un gran alcance de declaración después del alcance de inicialización, por lo que esto es mucho más fácil de declarar la variable que necesita donde lo necesita, por lo que lo verá en fron de usted.

2. No es absolutamente más rápido, ya que asigna memoria innecesaria y bombea la pila de funciones.

Este ejemplo de pseudo código mío:

public void A(double dParam) 
{         
    if(... condition ... ) {
        double dAnotherParam;
        string sParam; 
        ...
        // use local scope vars here
     }   
}

Pseudo código ejemplo él:

public void A(double dParam) 
{
    double dAnotherParam;
    string sParam; 

    dAnotherPatam = 0; 
    sParam = null;     

    if(... condition ... ) {
        ...
    }                   
 }

Alguna idea sobre el tema?

Gracias de antemano.

Author: A-K, 2010-10-20

15 answers

Esto es una cuestión de estilo. Mis consideraciones:

  1. Si el bloque de código es pequeño, al final no importará dónde coloque la declaración. Sin embargo, es preferible tener declaraciones más cercanas al uso, principalmente en bloques de código grandes. Primero, de esta manera puede asegurarse de que la variable no se modificó hasta ese punto en el bloque, y segundo, porque puede verificar el tipo y la inicialización de la variable más rápido.

  2. Además, es más rápido code declarando variables cerca de donde las usas't no tienes que volver al principio del ámbito solo para declarar una variable olvidada y luego retroceder.

  3. Esto no es más rápido o más lento. Las variables, sin importar dónde se declaren en el ámbito, tendrán su asignación e inicialización centrada al principio del ámbito. Esto se puede comprobar generando IL para el idioma.

Por ejemplo, el código:

static void Main(string[] args)
{
    var a = 3;

    if (a > 1)
    {
        int b = 2;
        a += b;
    }

    var c = 10;
    Console.WriteLine(a + c);   
 }

Genera el IL siguiente:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       24 (0x18)
  .maxstack  2
  .locals init ([0] int32 a,     // Declare a
           [1] int32 b,          // Declare b
           [2] int32 c)          // Declare c
  IL_0000:  ldc.i4.3             
  IL_0001:  stloc.0              
  IL_0002:  ldloc.0              
  IL_0003:  ldc.i4.1             
  IL_0004:  ble.s      IL_000c
  IL_0006:  ldc.i4.2
  IL_0007:  stloc.1
  IL_0008:  ldloc.0
  IL_0009:  ldloc.1
  IL_000a:  add
  IL_000b:  stloc.0
  IL_000c:  ldc.i4.s   10
  IL_000e:  stloc.2
  IL_000f:  ldloc.0
  IL_0010:  ldloc.2
  IL_0011:  add
  IL_0012:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0017:  ret
} // end of method Program::Main

Una cosa importante a tener en cuenta es que las variables en ámbitos internos, como la variable b, que estaba en el ámbito if, se declara en el ámbito del método por el compilador.

Espero que ayude.

 19
Author: Bruno Brant,
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
2010-10-20 16:13:18

Parece que tu colega es un viejo programador de C. Solía ser que tenías que colocar todas tus variables al principio del alcance, y la gente se acostumbró a hacerlo de esa manera.

En C#, es mejor colocarlos en el ámbito donde se necesitan. Esto tiene algunos beneficios, incluyendo:

  • Reduce el riesgo de error al reutilizar una variable de forma inapropiada, especialmente durante el mantenimiento a largo plazo
  • Está manteniendo la variable restringida dentro este ámbito de aplicación, que facilita la refactorización

El último punto es, en mi opinión, el más importante. Buena capacidad de mantenimiento y testabilidad dependen de la abiltiy para mantener sus métodos pequeños-y mantener las variables declaradas como se utilizan hace que la extracción de un método mucho, mucho más simple. No solo las herramientas se vuelven más efectivas, las refactorizaciones automáticas resultantes tienden a ser más simples (ya que la variable no es pasada por ref, etc.).


En cuanto a su código de ejemplo-yo personalmente lo haría diferente a cualquiera de ustedes. Todavía estás declarando tu variable al principio del ámbito interno. No los declararía hasta que realmente se usen:

public void A(double dParam) 
{         
    if(... condition ... ) {
        double dAnotherParam = GetValueFromMethod();

        // use local scope vars here

        // Later, as needed:
        string sParam = dAnotherParam.ToString(); 
     }   
}

Declararlos en la parte superior del ámbito (incluso en un ámbito interno), de nuevo, reduce la capacidad de las herramientas de refactorización automática de extraer métodos con éxito según sea necesario.

 30
Author: Reed Copsey,
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
2010-10-20 16:12:47

Es bastante simple y directo. Esta regla es lo que uso en mi código todo el día todos los días.

Declare variables en el ámbito más bajo con el que puede salirse con la suya.

Si solo está utilizando una variable dentro de un método, declare en el método, no es necesario colocarlo en el nivel de clase.

Editar: Parece que está preguntando sobre las variables de ámbito en los métodos específicamente.

En ese caso piénsalo de esta manera, si el uso de una variable depende de si una condición es verdadera, por qué declararla antes de pasar la condición. Estarías desperdiciando recursos al hacerlo.

 10
Author: ,
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
2010-10-20 15:35:08

Declarar variables en la parte superior de un método es una escuela muy antigua y es una resaca de C. Me enseñaron exactamente lo mismo en la Universidad.

Hoy en día tratamos de mantener los métodos muy pequeños y magros con nombres de parámetros y métodos significativos. Es mucho más limpio declarar e inicializar una variable dentro del ámbito en el que se va a utilizar. Si hay muchas de estas áreas de código con en un método dado, puede ser una indicación de que debe refactorizar a menor más fácil de leer método.

La única vez que consideraría hacer esto es cuando desea inicializar algo dentro de una instrucción try catch finally donde desea hacer algo con el objeto con en el bloque catch o finally.

SomeObject someObject = null;

try
{
    someObject = GetSomeObject();
    return someObject.DoSomething();
}
finally
{
    if (someObject != null) someObject.DoSomethingElse();
}

La mayoría de las veces todo lo que desea hacer es limpiar el objeto para que una instrucción using sea más que adecuada, pero hay momentos en los que se necesita.

 5
Author: Bronumski,
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
2010-10-20 15:42:25

En términos de que el código se ejecuta más rápido con todas las variables declaradas en la parte superior de la rutina, yo diría que el oppposite es el caso, si hay alguna diferencia en absoluto. No soy experto en esto, pero asumo que la recolección de basura será más eficiente al declarar variables en el alcance más bajo que pueda. De esa manera la limpieza puede ocurrir antes.

Además, al poner las variables cerca del código que las usa, mejora la legibilidad IMO.

Una analogía es que es la diferencia entre tener notas al margen (colocadas justo al lado del texto que está leyendo), vs.una pared de notas al pie en la parte inferior de la página (no está seguro de qué nota al pie se relaciona con qué texto sin hacer algunas referencias cruzadas usted mismo).

 4
Author: RedFilter,
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
2010-10-20 15:27:48

El rendimiento no importa porque el compilador se encargará de esto. Al compilador no le importa si los declaras en la parte superior del método o justo antes de usarlos.

Sin embargo, tener 20 declaraciones en la parte superior en lugar de declarar la variable cuando la usa no hace que el código sea más legible.

Me gustaría ir por la primera opción.

 4
Author: Pieter van Ginkel,
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
2010-10-20 15:28:10

El punto de su colega es de la programación de la vieja escuela. No es que sea malo, pero esto viene del lenguaje ensamblador.

Al principio de un código ensamblador, tenía que declarar el registro DS (Segmento de datos) que hacía alguna asignación en la pila para reservar algo de memoria. Aquí hay un ejemplo de código:

.MODEL SMALL

.DATA 
    myVariable1 DW "This is my first variable"
    myVariable2 DB "Second var"

.CODE 'code segment

:ProgramStart

    MOV AX,01h
    ...

:ProgramEnd

Como ya han dicho los demás, en los programas C, las declaraciones de variables tenían que estar al principio de una función. Al igual que necesitabas escribir tus funciones definiciones al principio de su programa C, antes de la función main(), luego escribir su cuerpo después de su función principal, de lo contrario su función (o variable) no fue reconocida. Así que sí, esto fue más rápido porque la dirección de la variable ya era conocida por el código en línea generado.

Sin embargo, con la llegada de la OOP y la programación de eventos, tendemos a permanecer lo más cerca posible del evento. Lo que quiero decir se reanuda siendo tu punto de vista. Los compiladores de hoy analizan el código para tales variables a lo largo del código y lo convierten en un código CLR manejable. Así que esto ya no marca la diferencia, hablando de rendimiento. En la programación actual, tendemos a hacer que el código sea lo más fácil de leer y entender posible. Dicho esto, esto incluye declaraciones de variables.

Declarar una variable al principio de una función, y usarla solo 20 líneas más no sirve de nada, además tiende a hacer que el programa sea más difícil de entender. Por ejemplo, estás analizando un fragmento de código, ¡luego salta! un aparece el nombre de la variable, pero no hay ninguna declaración. ¿De dónde viene esta variable? Tendrá que desplazarse hacia arriba (o ir a la definición) para averiguar qué es esta variable. Mientras tanto, es posible que haya perdido su idea sobre el propósito de la rutina que estaba leyendo y tratando de entender. Que sea tres o más veces, y su perdido tratando de entender el código.

Es mejor tener un punto de vista ágil y ágil del propósito del código. Es decir, no declarar cualquier variable innecesaria antes de que realmente es indispensable. Escribir de esta manera evitará que uno siempre se desplace hacia arriba y hacia abajo mientras lee o escribe el código de un programa.

Estos son mis dos centavos. Espero ser lo suficientemente claro en lo que he estado tratando de explicar.

Espero que esto ayude de todos modos!

 4
Author: Will Marcouiller,
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
2010-10-20 16:42:27

Declare las variables en el ámbito que desea utilizar.

 3
Author: bevacqua,
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
2010-10-20 15:25:16

Re: legibilidad, tienes razón. Y también considerar que declarar variables en un ámbito más alto pierde cualquier información sobre dónde son relevantes. Un usuario que lo mira necesita leer todo el método para ver dónde se usa una variable. Además, hay más riesgo de usar erróneamente la variable incorrecta.

 2
Author: Andy,
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
2010-10-20 15:31:10

Para agregar otro punto, es posible que no siempre desee inicializar las variables que se declaran a nivel de clase. A veces es posible que desee que estas cosas sean nulas y activamente prueba para eso.

Además, mencionas que tienes métodos muy largos... los métodos deben ser funcionales, hacer un propósito particular y luego regresar al flujo del programa. Así que los métodos largos a menudo se pueden refactorizar en código manejable más pequeño.

 2
Author: jimplode,
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
2010-10-20 15:34:13

En mi opinión, la declaración al principio de la función es de manera menos legible que la declaración en el alcance más bajo posible. Debe prestar atención a que su código es legible ya que esto es mucho más importante que esta optimización de micro velocidad.

 1
Author: Marius Schulz,
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
2010-10-20 15:30:01
  1. No es legible como si tuviera una función larga, tiene que tener un gran alcance de declaración después del alcance de inicialización

Esto solo indica que necesita refactorizar el código. De hecho, es bueno que las declaraciones te obliguen a pensar estas cosas.

No es absolutamente más rápido, ya que asigna memoria innecesaria y bombea la pila de funciones.

Idealmente, no lo hace. Si alguna rama de su código necesita asignar objetos que son ortogonales al resto de la función, es mejor descargar esta rama en una función separada.

De esta manera, también se mantiene el principio de "declarar dónde lo usa".

 1
Author: himself,
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
2010-10-20 15:33:09

No es legible como si tuvieras un función larga, usted tiene que tener enorme alcance de la declaración después de la inicialización alcance, por lo que esto es mucho más fácil de declare la variable que necesita donde lo necesitas, así que lo verás en de ti.

No estoy entendiendo cómo eso sería más legible tampoco. Aleja la declaración de la sección de código que pretende usarla, lo que resulta en la pérdida de pistas de proximidad.

No Es absolutamente más rápido, a medida que asignar memoria innecesaria y bomba la pila de funciones.

El argumento de que es más rápido también es incorrecto. No importa en qué parte del método se declara una variable que todavía ocupa la misma cantidad de espacio en la pila. Así que no hay diferencias fundamentales en el rendimiento de las que soy consciente1. Sin embargo, podría argumentar que las declaraciones con inicializaciones en línea consumirían ciclos de CPU adicionales si se considera que la inicialización es innecesario. Por ejemplo, puede declarar e inicializar una variable dentro de un bloque if en cuyo caso la inicialización se produce solo si la ejecución se sumerge en ese bloque. Contrasta eso con lo que sucedería si hicieras la declaración y la inicialización en la parte superior del método.

1supongo que habrá algunos extrañas consecuencias de método inline o similares que pudieran afectar esto, pero lo dudo.

 1
Author: Brian Gideon,
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
2010-10-20 15:39:24

Una regla general que siempre he seguido es rellenar las variables lo más cerca posible de su declaración, esto significa no declarar una variable en la línea 10 y luego darle un valor inicial en la línea 100.

 1
Author: kyndigs,
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
2010-10-20 15:40:18

Pascal fue uno de los idiomas posteriores que aprendí, donde todo tenía que ser declarado por adelantado según el ejemplo de su buddie. Perdónenos, los lenguajes anteriores no permitían variables con un alcance cercano à la.NET, por lo que "los viejos hábitos no mueren".

El rendimiento ya no es un problema, el costo en la programación es la mano de obra. Los compiladores se han vuelto más inteligentes que la mayoría de nosotros, por lo que el verdadero problema es evitar errores. (Perdóname por ilustrar en VB, simplemente hago menos errores tipográficos.)

Comparar:

Dim X as integer = 0
' 100 lines of drivel, where I'm forgetting about X
For X = 1 To 10
  If pornographic(X) then ' Pron integers, geek alert!
    Viagra(X)
  End if
Next
' 50 lines of drivel, X lurks with his raincoat

If X >= 10 Then ' Compiles. X=11, if you're damn lucky
  ' make a nasty mistake
End if

No te rías, pasa todos los días.

Con:

' 100 lines of drivel, nothing lurid in sight
For X As Integer = 1 To 10
  If pornographic(X) then ' Pron integers, geek alert!
    Viagra(X)
  End if
Next
' 50 lines of drivel, X is no more

If X >= 10 Then ' *** FAILS AT COMPILE-TIME ***
  ' *** CAN'T *** make a nasty mistake
End if

Respuesta fácil, ¿verdad?

Maurice

P.d. Me olvidé de declarar: Viagra Protegida Por el Público (clipno Como Película)...

 1
Author: smirkingman,
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
2010-10-20 19:18:03