Convenciones para escribir código

Solution Development Kit
Convenciones para escribir código .NET
Página de inicio | solucion.biz

Convenciones para escribir código .NET

Las convenciones para escribir código .NET son directivas para programar en .NET, específicamente con C#, y están orientadas a la estructura física y apariencia del código, no a la lógica del mismo.

Versión 1.3

Modificado el 17 de septiembre de 2004

© 2004 solucion.biz. Todos los derechos reservados. Envienos su comentarios y sugerencias al equipo de desarrollo.


Objetivo

Este documento contiene las convenciones que se deben utilizar en el código escrito en solucion.biz para la plataforma .NET.

Este documento esta orientado principalmente al lenguaje C#, para otros lenguajes de .NET Framework se deben seguir convenciones semejantes.


Alcance

A todo el código que utilice .NET Framework como plataforma.


Convenciones en el documento

La siguiente tabla muestra las convenciones tipográficas utilizadas en este documento.

Convenio | Ejemplo | Descripción
Negrita | método Do | Identifica elementos predefinidos de programación, por ejemplo, clases, interfaces, métodos, funciones, macros, estructuras, enumerativos, campos, operadores, constructores, propiedades, eventos, tipo de datos, directivas, palabras claves, instrucciones, excepciones, atributos, llaves y valores del registro. También indica entradas de usuario tal y como tienen que ser escritas.
Itálica | Nombre | Indica textos a rellenar, por ejemplo parámetros de funciones o métodos, nombres de módulos y entradas que el usuario debe dar.
Letras mayúsculas | ENTER | Indica nombres de teclas o secuencia de teclas.
Signo más | ALT+F1 | Indica combinación de teclas.


Referencias

[1] Documentación de Visual Studio .NET 2003


Comentarios

Se pueden utilizar tres tipos de comentarios: comentarios de implementación, comentarios de documentación y comentarios especiales. Los comentarios de implementación son los estándar encontrados en C#, delimitados por /*...*/, y //. Los comentarios de documentación son delimitados por bloques ///...///.

Todos los comentarios se realizaran en lenguaje español de la forma más clara y precisa posible sin utilizar estructuras sintácticas complejas. Si un comentario no se entiende a la primera se debe tratar de rescribir de una forma más clara.

Los comentarios deber ser usados para dar una idea general del código y brindar información adicional que no está disponible en el propio código. Los comentarios deberían contener solo información que es relevante para leer y entender el código, no debería incluir información redundante o evidente.

Decisiones de diseño no triviales o poco obvias son buenas candidatas para comentarios, pero evite usar información que ya está presente en el código de forma clara. Es fácil que comentarios redundantes queden desactualizados. En general evite comentarios que quedaran desactualizados a medida que el código se desarrolla.

Nota: La frecuencia de comentario de implementación generalmente refleja poca calidad en el código. Cuando se sienta obligado a poner comentarios, considere rescribir el código para hacerlo más claro.


Comentarios de documentación

Los comentarios de documentación describen las constantes, enumerativos, interfaces, clases, constructores, métodos, propiedades y campos.

Cada comentario de documentación se inicia con ///. Este comentario debería aparecer justo antes de la declaración:

   /// <remarks>

   /// Esto es un comentario de documentación antes de una clase.

   /// </remarks>

   public class Foo

   {

        ...

   }

Si es necesario dar información que no es apropiada para la documentación utilice comentarios de implementación. Por ejemplo, los detalles de la implementación de una clase deben ir en un comentario de bloque que siga la instrucción de declaración de la clase, y no en el comentario de documentación de la clase.

Dentro de este comentario de documentación pueden ir las siguientes etiquetas:

   <c> <para> <see> <code> <param> <seealso> <example> <paramref> <summary> <exception> <permission> <value> <include> <remarks> <list> <returns> <note>

Siga los siguientes consejos al crear los comentarios de documentación:

· Evite el uso de etiquetas HTML, solo cuando sea imprescindible, por ejemplo no utilice la etiqueta <P> para denotar un párrafo, en su lugar utilice <para>. Evite el uso de la etiqueta <SPAN>, en su lugar utilice <c> si es código o otra etiqueta para obtener el efecto deseado.

· No utilice las etiquetas <I> para itálica o <B> para negritas en el caso que representa parámetros o palabras claves, en su lugar utilice <paramref> y <see langword> respectivamente.

· Escriba las etiquetas de comentarios en minúsculas y las etiquetas HTML en mayúsculas, así se evita confundirlas.

· Revise los avisos del compilador para comprobar los comentarios erróneos, como referencias no validas o falta de parámetros.

· Utilice la etiqueta <para> para dividir volúmenes de texto.

· Utilice la etiqueta <sumary> para un resumen breve.

· Utilice la etiqueta <value> para describir el tipo de una propiedad y su valor por defecto.

· Utilice la etiqueta <remarks> para agregar información adicional.

Para otros lenguajes es aconsejable utilizar el mismo esquema de comentarios. Estas etiquetas con compatibles con la versión NDoc de solucion.biz.


<c>

Utilice la etiqueta <c> para incluir código dentro de la misma línea de texto. Para bloques de texto utilice la etiqueta <code>.

/// El recurso debe tener nombre <c>Strings</c>.


<code>

Utilice la etiqueta <code> para especificar bloques de texto, normalmente dentro de la etiqueta <example>.

Puede agregar el atributo lang para definir el lenguaje en el que se ha escrito el código.

/// <code lang="C#">

///   ResourceManager rm = new ResourceManager(resourceName, a);

/// </code>.


<example>

Utilice la etiqueta <example> para incluir un ejemplo, normalmente se incluye una etiqueta <code> si es un ejemplo que incluye código.

/// <example>

/// El siguiente ejemplo obtiene el valor de configuración

/// llamado a <see cref="Settings.ApplicationName"/> desde el archivo de

/// configuración de la aplicación:

/// <code lang="C#">

///   applicationName = ConfigurationSettings.AppSettings[Settings.ApplicationName];

/// </code>

/// </example>


<exception>

Utilice la etiqueta <exception> para documentar las excepciones que puede iniciar un método. Debe ser el último bloque de comentarios que debe aparecer.

/// <exception cref="ApplicationException">

///   Si no se puede conectar a la base de datos.

/// </exception>


<list>

Utilice la etiqueta <list> para definir una lista (numerada o no) o tabla. El atributo type puede ser bullet, number o table.

/// Esto es una lista no numerada.

/// <list type="bullet">

/// <item>

/// <term>Termino 1</term><description>Primera entrada de la lista.</description>

/// </item>

/// <item>

/// <description>Segunda entrada de la lista.</description>

/// </item>

/// </list>

///

/// Esto es una tabla.

/// <list type="table">

/// <listheader>

/// <description>Encabezado columna 1</description>

/// <description>Encabezado columna 2</description>

/// </listheader >

/// <item>

/// <description>Fila 1, columna 1.</description>

/// <description>Fila 1, columna 2.</description>

/// </item>

/// <item>

/// <description>Fila 2, columna 1.</description>

/// <description>Fila 2, columna 2.</description>

/// </item>

/// </list>


<note>

Utilice la etiqueta <note> para incluir notas especificas en el comentario.

Se puede incluir el atributo type para definir el tipo de nota, se pueden utilizar los siguientes valores:

§ caution: Define una nota de precaución.

§ inheritinfo: Define una nota para los herederos.

§ inotes: Define una nota para los implementadores.

/// <note type="inotes">

/// Las clases descendientes deben especificar un valor a la

/// propiedad <see cref="ApplicationPathName"/>

/// en su inicialización.

/// </note>


<para>

Utilice la etiqueta <para> para delimitar párrafos dentro de otras etiquetas como <remarks>, <sumary> y <value>.

Puede agregar el atributo lang para definir el lenguaje al que se aplica el párrafo.

No utilice las etiquetas HTML <P>, <DIV> ni <SPAN>.

/// <remarks>

/// Clase base para los valores de configuración de la aplicación.

/// <para>

/// Los valores de configuración se guardan en el registro de Windows

/// o en el archivo de configuración <see cref="ApplicationName.Settings"/>.

/// </para><para>

/// Tambien se pueden sobreescribir utilizando el archivo de configuración

/// de la aplicación.

/// </para>

/// </remarks>

/// <para lang="C#">

/// En C#, esta propiedad es el indizador de la clase.

/// </para>


<param>

Utilice la etiqueta <param> para definir los parámetros de un método, constructor o indizador.

/// <param name="message">Mensaje de error.</param>

/// <param name="ex">Excepción con información del error.</param>


<paramref>

Utilice la etiqueta <paramref> para hacer referencia a parámetros dentro de otros textos.

No utilice la etiqueta <I></I> de HTML.

/// En el parámetro <paramref name="message"/> puede pasar

/// un mensaje de error.


<remarks>

Utilice la etiqueta <remarks> para agregar información adicional no incluida en la etiqueta <sumary> o <value>.

/// <remarks>

/// Los valores se toman desde el archivo de configuración.

/// </remarks>


<returns>

Utilice la etiqueta <returns> para comentar el valor de retorno de un método.

/// <returns>Cadena localizada según la configuración cultural actual.</returns>


<see>

Utilice la etiqueta <see> para hacer referencia a otra información dentro de la misma línea de texto. No es lo mismo que la etiqueta <seealso>.

La etiqueta <see> puede tener los siguientes atributos:

§ cref: Para hacer referencia a otro tipo mediante un hipervínculo que contiene sus propios comentarios. Por ejemplo, otra clase o propiedad. Se puede incluir el atributo nolink si no se debe incluir el hipervínculo, solo la información del tipo.

§ href: Para hacer referencia a otra información mediante un hipervínculo. Por ejemplo, a una página Web en Internet.

§ langword: Para hacer referencia a una palabra clase, por ejemplo, true o throw. Se definen los siguientes valores especiales:

o         null: Una referencia nula.

o         sealed: Clase sellada.

o         static: Miembro estático (preferentemente un método).

o         abstract: Miembro abstracto (preferentemente un método).

o         virtual: Miembro virtual.

/// Obtiene el valor del nivel de traza actual, es uno de

/// los valores de la enumeración <see cref="System.Diagnostics.TraceLevel"/>.

/// Puede ver más información en <see href="http:\\www.solucion.biz"/>.

/// Pueder ser un objeto <see cref="Application"/> o <see langword="null"/>.

/// <see langword="true"/>.


<seealso>

Utilice la etiqueta <seealso> para hacer referencia a otra información que aparece en la sección Vea también. La etiqueta debe parecer dentro de otra etiquita <remarks>.

/// <seealso cref="System.Diagnostics.TraceLevel"/>

/// <seealso cref="Bizion.Global"/>


<summary>

Utilice la etiqueta <summary> para describir un tipo o método. Utilice <remarks> para incluir información adicional.

/// <summary>

/// Clase que incluye un conjunto de servicios basicos.

/// </summary>


<value>

Utilice la etiqueta <value> para describir una propiedad. Utilice <remarks> para incluir información adicional.

/// <value>

/// Objeto de tipo <see cref="String"/> con el nombre, no se permite

/// <see langword="null"/>.

/// Su valor por defecto es la cadena vacía (<see cref="String.Empty"/>).

/// </value>


Comentarios de implementación

Los comentarios de implementación son comentarios específicos a la implementación y que no son necesarios para utilizar la funcionalidad, pero si necesario para mantenerla.

Los comentarios deber ser usados para dar una idea general del código y brindar información adicional que no está disponible en el propio código. Los comentarios deberían contener solo información que es relevante para leer y entender el código, no debería incluir información redundante o evidente.


Comentario de bloque

Los comentarios de bloque son usados para dar descripción de archivos, métodos, estructuras de datos y algoritmos. Un comentario de bloque puede ser usado al comienzo de cada archivo y antes de cada método. Ellos también pueden estar en otros lugares, como dentro de un método. Los comentarios de bloques que están dentro de los métodos deben ser indentados al mismo nivel que el código que ellos describen. Los comentarios de bloques no deben encerrar códigos que no se quiere que se compilen, para esto utilice comentarios hasta fin de línea.

Un comentario de bloque deber ser precedido por una línea en blanco, para apartarlo del resto del código.

En un comentario de bloque cada línea comienza con un *.

   /*

    * Esto es un comentario de bloque

    */


Comentario de una sola línea

Pequeños comentarios pueden aparecer en una sola línea al mismo nivel de indentación que el código que le sigue. Si un comentario no puede ser escrito en una sola línea, debería usarse un comentario de bloque. Un comentario de una sola línea debe ser precedido por una línea en blanco sí el código anterior esta al mismo nivel de indentación.

   if (condition)

   {

        /* Esto es un comentario de una sola línea...*/

        ...

   }


Comentario al final

Pequeños comentarios pueden aparecer en la misma línea de código que ellos describen, pero lo suficientemente separados. Si más de un comentario de este tipo aparece en el código, todos deben estar indentados al mismo nivel. Evite comentarios estilo lenguaje ensamblador.

   if (condition)

   {

        return ExpresionTrue();        /* comentario uno */

   }

   else

   {

        return ExpresionFalse();       /* comentario dos */

   }


Comentario hasta fin de línea

El comentario que comienza con // termina con una nueva línea. Este tipo de comentario no debería ser usado en varias líneas consecutivas, para esto utilice un comentario de bloque. Solo en el caso que se quiera comentar un código para que no compile, se debe utilizar este tipo de comentario en más de una línea.

   if (foo == 1)

   {

        // Hacer algo

        ...

   }

   else

   {

        return false; // Explicar aquí por qué.

   }

   // ESTE CODIGO NO COMPILA

   //if (bar == 1)

   //{

   //   ...

   //}

   //else

   //{

   //   return false;

   //}


Comentarios especiales

Los comentarios especiales aparecen en la lista de tares de Visual Studio .NET, puede utilizar los siguientes comentarios especiales:

· TODO: Para indicar que falta algo por hacer.

· UNDONE: Para indicar algo temporal y debe ser deshecho.

· HACK: Para indicar que algo está fraudulento pero trabaja.

Ejemplos:

   // TODO: Falta completar el método

   // HACK: Esto explota si hay más de 100 elementos

   // UNDONE: Cambiar por una tabla hash


Declaraciones

Los programas se organizan mediante el uso de espacios de nombres, que pueden contener declaraciones de tipo y declaraciones de espacio de nombres anidadas.

Vea la sección Nombres para una descripción de la nomenclatura de los nombres de tipos y espacios de nombres.


Lugar

Las declaraciones se deben ubicar al principio del bloque que la utiliza. Un bloque es cualquier código encerrado por { y }. No espere a declarar variables justamente antes de utilizarlas, esto puede confundir a otros programadores y hacer difícil el mantenimiento del código.

     public void MyMethod()

   {

        int int1; // comienzo del bloque del método

        if (condition)

        {

           int int2; // comienzo del bloque del "if"

           ...

        }

   }

Una posible excepción para esto son las variables para los índices de los ciclos, las cuales pueden ser declaradas en la instrucción for o foreach.

   for (int i = 0; i < maxLoops; i++)

   {

        ...

   }

Evitar declaraciones locales que ocultan declaraciones de niveles más altos. Por ejemplo:

   int count;

   ...

   public void Func()

   {

        if (condition)

        {

           int count; // EVITAR!!!

           ...

       }

        ...

   }

Se recomienda una declaración por línea, nunca se deben declara tipos diferentes en una misma línea

Siga las siguientes reglas:

· No dejar espacio entre el nombre del método y el paréntesis ( que comienza la lista de parámetros.

· La llave abierta { y cerrada } aparecen siempre en la misma columna.


Modificadores

Los modificadores se utilizan para modificar declaraciones de tipos y miembros de tipos.

El primer modificador en la lista de modificadores de un miembro debe ser el modificador de acceso (public, private, internal o protected) y luego el resto de modificadores, con el siguiente orden relativo:

§ Primero el modificador static antes que los modificadores const o readonly.

§ Primero el modificador new antes que los modificadores virtual o abstract.


Depuración

Se deben utilizar los mecanismos de traza y aserción de forma intensiva.

El mecanismo de traza permite rastrear condiciones excepcionales en la ejecución.

El mecanismo de aserción se basa en el concepto de invariante. Un invariante es una condición lógica (verdadera o falsa) cuyo valor debe mantenerse. Para cualquier operación es necesario definir precondiciones (invariantes asumidos por la operación) y poscondiciones (invariantes satisfechos por la operación).

Pruebe cada método lo antes posible, compruebe que hace lo que se supone y valida correctamente sus parámetros. Si se esperan datos de entrada desde el usuario, validar estos datos.

Cuando se detecta un problema en el código, este seguro de comprender su naturaleza y alcance (los errores no siempre son lo que parecen ser) y corríjalo inmediatamente. Evitar errores o código dudoso con el pretexto de corregirlo posteriormente no es buena idea, puede ser que nunca lo corrija, o cuando llegue el momento de corregirlo la idea no estará tan clara como cuando escribió el código.

Al hacer un cambio en el código, use un comentario que lo documente. Considere mantener el código anterior dentro de un comentario hasta que este seguro que el nuevo código funciona correctamente.

Para la depuración de utilizarán las clases del espacio de nombres Systems.Diagnostics.

En Visual Studio .NET la clase Debug no genera código en la versión de lanzamiento, solo lo genera en la versión de depuración. A diferencia de la clase Trace que genera código en la versión de lanzamiento y depuración. Las dos clases tienen el mismo conjunto de métodos y propiedades.

Se deben definir dos modificadores del nivel de seguimientos (TraceSwitch), uno para la versión de depuración (debugSwitch) y otro para la versión de lanzamiento (releaseSwitch).

Para establecer los niveles de los modificadores, edite el archivo de configuración correspondiente a la aplicación. En el archivo, se pueden agregar los modificadores y se puede establecer su valor. El archivo de configuración debería tener el formato que se muestra en el siguiente ejemplo:

<configuration>

    <system.diagnostics>

       <switches>

          <add name="debugSwitch" value="3" />

          <add name="releaseSwitch" value="1" />

       </switches>

    </system.diagnostics>

</configuration>


Aserción

Utilizar las aserciones para comprobar condiciones lógicas en el código. Si un código falla por un error es fácil detectarlo, pero si utiliza o crea datos inválidos es difícil de detectar, y es aquí donde se deben utilizar las aserciones. Normalmente se utilizan a la entrada y salida de un método o propiedad aplicados al estado del objeto, no a los argumentos del método.

Es útil crear un método Assert en cada clase que chequea que el estado de la clase es valido, se puede llamar a este método al inicio y final de cada método normal para comprobar que el método no corrompe el estado del objeto.

Si se utiliza una aserción, esta debe ser verdadera según la lógica del código, si es falsa, es que hay un error lógico del mismo. Por ejemplo, la cantidad de elementos en una colección tiene que ser siempre mayor o igual que cero, esto se debe comprobar con una aserción, pero eliminar un elemento con la colección vacía se debe manipular como un error, quizás lanzando una excepción y no con una aserción.

No utilice aserciones con efectos colaterales, por ejemplo:

   Debug.Assert(i++ > 0);

No utilice aserciones donde se debe utilizar código de manipulación de errores. Las aserciones detectan errores lógicos en el código que no deben existir, no errores que puedan ser lógicos y validos. Solo utilice aserciones con un código de error cuando se supone que ese código no debe manipular lógicamente ese error. Por ejemplo:

   result = MyDrawRoutine();

   Debug.Assert(result <> 0, "result is zero!!!");

No es un buen uso de la aserción. Solo usarlo en el caso en que se supone que el error es manipulado antes, por ejemplo:

   result = MyDrawRoutine();

   ' aqui va el codigo que debe manipular el codigo de error

   ' si llega aqui es un error logico

   ' el codigo anterior deberia manipular el error

   Debug.Assert(result <> 0, "result is zero!!!");

No utilizar aserciones en la comprobación de resultados en llamadas a métodos o propiedades del sistema.


Traza

Utilice el mecanismo de traza para rastrear condiciones excepcionales en la ejecución. Se pueden utilizar los siguientes métodos de la clase Debug (Trace) para implementar las trazas: Write, WriteIf, WritleLine, WriteLineIf y Fail.

   Debug.Fail("Invalid value: " + value.ToString(), "Resetting value to newValue.")

   if (generalSwitch.TraceVerbose)

     {

        Debug.WriteLine("Object is not valid for this category.");

   }


Legibilidad

Para mejorar la legibilidad del código se utilizan los espacios en blanco y la indentación. Utilícelos de forma consistente, pero si abusar de ellos.

Las siguientes secciones incluyen información adicional.


Espacios en blanco

Los espacios y líneas en blanco se utilizan para dar claridad al código separando secciones lógicas.

Siga las siguientes reglas al usar los espacios en blancos:

· Las palabras claves seguidas por un paréntesis deben separarse con un espacio del paréntesis.

        for (int i = 0; i < 10; i++)

        .

        .

        .

           if (i == 2)

        .

        .

        .

        while (j == 2)

· No usar un espacio entre el nombre de un método y su paréntesis, esto permite diferenciarlo de las palabras claves.

        if (SomeMethod())

        .

        .

        .

        switch (OtherMethod())

· Un espacio en blanco debe aparecer después de la coma en la lista de argumentos.

     public int Add(int a, int b)

        .

        .

        .

     int c = Add(a, b);

· Todo operador binario debe ser separado de sus operandos por un espacio. Los operadores unarios no deben separarse de su operando:

        a += c + d;

        a = (a + b) / (c * d);

        while (d++ = s++)

        {

           n++;

        }

        p.Init(1);

· Expresiones en la instrucción for deben ser separadas por un espacio en blanco después del punto y coma:

        for (expr1; expr2; expr3)

        {

           ....

        }

· Las conversiones de tipo deben ser seguidos por un espacio en blanco:

        MyMethod((byte) aNum, (int) x);

     MyFunc((int) (cp + 5), ((int) (i + 3)) + 1); // esto es pesimo

Las líneas en blanco mejoran la legibilidad del código permitiendo agrupar secciones de código relacionado lógicamente.

Dos líneas en blanco deben usarse siempre:

· Entre secciones de archivos.

· Entre definiciones de clases.

Una línea en blanco debe usarse siempre:

· Entre métodos, propiedades, campos o eventos.

· Entre la definición de variables locales y la primera instrucción

· Antes de un comentario de bloque o un comentario de una línea

· Entre secciones de código dentro de un método para mejorar la legibilidad.


Indentación

Como unidad de indentación se debe utilizar cuatro espacios. La tabulación se debe poner a cuatro espacios, y utilizar la tabulación para crear la indentación.

Se debe evitar el uso de líneas de más de 70 caracteres, como máximo 80. Líneas más largas hacen necesario el uso de las barras de desplazamiento, lo que hace difícil leer el código.

Cuando una expresión no cabe en una sola línea, divida esta de acuerdo a los siguientes principios generales:

· Dividir después de la coma.

· Dividir antes de un operador.

· Dividir al mayor nivel posible.

· Alinear la nueva línea con el comienzo de la expresión en la línea anterior.

· Si aplicando la regla anterior queda un código confuso, o muy pegado al margen derecho, solo indente dos tabulaciones.

Algunos ejemplo de división en llamadas a métodos:

   Method1(longExpression1, longExpression2, longExpression3,

           longExpression4, longExpression5);

   Method2(longExpression1,

           function2(longExpression2, longExpression3));

A continuación dos ejemplos utilizando expresiones aritméticas. El primero es preferido, ya que la división ocurre fuera de la expresión dentro del paréntesis, lo cual está a mayor nivel.

   longName1 = longName2 * (longName3 + longName4 - longName5)

                + 4 * longname6;                    // PREFERIDO

   longName1 = longName2 * (longName3 + longName4

                             - longName5) + 4 * longname6;   // EVITAR

Los siguientes dos ejemplos son declaraciones de métodos. El primero es el caso convencional, el segundo debería indentar demasiado a la derecha si usara la indentación estándar, por lo que utiliza una indentación de dos tabulaciones.

   //INDENTACION CONVENCIONAL

   public int X(int anArg, object anotherArg,

                string yetAnotherArg, object andStillAnotherArg)

   {

        ...

   }

   //INDENTACION A 8 ESPACIO PARA EVITAR PEGARSE A LA DERECHA

   public unsigend long LongLongLongLongLongLongMethodName(int anArg,

           object anotherArg, atring yetAnotherArg,

           object andStillAnother)

   {

        ...

   }

La división de la línea en instrucciones if debe usar generalmente indentación dos tabulaciones, ya que la indentación normal hace difícil leer el cuerpo.

   //NO USE ESTA INDENTACION

   if ((condition1 && condition2)

        || (condition3 && condition4)

        ||!(condition5 && condition6))   //DIVISION MALA

   {

        DoSomethingAboutIt();            //ES FACIL CONFUNDIR ESTA LINEA

   }

   //EN CAMBIO USE ESTA

   if ((condition1 && condition2)

           || (condition3 && condition4)

           ||!(condition5 && condition6))

     {

        DoSomethingAboutIt();

   }

   //O ESTA

   if ((condition1 && condition2) || (condition3 && condition4)

           ||!(condition5 && condition6))

   {

        DoSomethingAboutIt();

   }

Una expresión ternaria se puede dividir de las siguientes formas, solo cuando no quepa en una sola línea:

   alpha = (aLongBooleanExpression) ? beta

                                  : gamma;

   alpha = (aLongBooleanExpression)

             ? beta

             : gamma;


Instrucciones

Cada línea debe tener a lo máximo una instrucción:

   i += b;

   b++; c--; // EVITAR!!!

Las instrucciones compuestas son aquellas que encierran instrucciones dentro de llaves { y }. Las instrucciones que se encuentran dentro de la instrucción compuesta deben indentarse una tabulación. La llave { que abre y la que cierra } se ponen en la misma columna. Siempre utilizar instrucciones compuestas en bloques de control, incluso cuando sea solo una instrucción, esto hace más fácil entender el código y mantenerlo.

   if (condition)

   {

        return factor;

     }

   else

   {

      i++;

      return i * factor;

   }


checked, unchecked

Las instrucciones y operadores checked y unchecked deben tener la siguiente forma:

   checked

   {

        // statements;

   }

   unchecked

   {

        // statements;

   }

   checked (statement);

   unchecked (statement);


do-while

La instrucción do-while debe tener la siguiente forma:

   do

   {

        //statements;

   }

   while (condition);


for

La instrucción for debe tener la siguiente forma:

   for (initialization; condition; update)

   {

         statements;

   }

Una instrucción for vacía debe tener la siguiente forma:

   for (initialization; condition; update);

Las instrucciones for vacías deben evitarse y solo usarlas cuando representen la solución natural.

Nunca utiliza instrucciones for por instrucciones while:

   for ( ; ; )

   {

        // EVITAR

   }

   for ( ; condition; )

   {

        // EVITAR

   }


foreach

La instrucción foreach debe tener la siguiente forma:

   foreach (Type identifier in expresion)

   {

         statements;

   }

Tenga en cuenta que se producirá un error en tiempo de compilación si la instrucción incrustada intenta modificar la variable de iteración (por medio de asignación o utilizando los operadores ++ y --) o bien si la pasa como un parámetro ref o out.


if-else

Las instrucciones if-else deben tener la siguiente forma:

   if (condition)

   {

        //statements;

   }

   if (condition)

   {

        //statements;

   }

   else

   {

        //statements;

   }

   // EVITAR ESTE TIPO DE CONTRUCCION, SI SE PUEDE CON switch

   if (condition)

   {

        //statements;

   }

   else if (condition)

   {

        //statements;

   }

   else if (condition)

   {

        //statements;

   }

Siempre use { y } en instrucciones if, aunque las llaves encierren una sola instrucción.

Evite esto:

   if (condition) //EVITAR!!! ESTO OMITE "{" y "}"

        statement;


lock

La instrucción lock debe tener la siguiente forma:

   lock (expression)

   {

        // statements;

   }

En la instrucción lock también se puede utilizar objetos de tipo System.Type para controlar el acceso a los métodos estáticos (de clase):

   lock (typeof(someObject))

   {

        // statements;

   }


return

Una instrucción return no debería utilizar paréntesis a menos que esto hiciera más obvio el valor de retorno:

   return;

     return myDisk.Size();

     return ((size <> 0) ? size : defaultSize);


switch

La instrucción switch debe tener la siguiente forma:

   switch (condition)

   {

        case ABC:

           //statements;

         goto case DEF

        case DEF:

           //statements;

           break;

        case XYZ:

           //statements;

         break;

default:

        //statements;

           break;

   }

Toda instrucción switch debe tener siempre un caso default, aunque este vació.


try-catch-finally

Las instrucciones try-catch-finally deben tener la siguiente forma:

   try

   {

        //statements;

   }

   catch (ExceptionClassEx e)

   {

        //statements;

   }

   catch (ExceptionClass e)

   {

        //statements;

   }

   finally

     {

        //statements;

     }


using

La instrucción using debe tener la siguiente forma:

   using (ResourceType resource = expression)

   {

        // resource is READONLY

        // statements;

   }

También se puede utilizar de la siguiente forma:

   using (expression)

   {

        // statements;

   }


while

La instrucción while debe tener la siguiente forma:

   while (condition)

   {

        // statements;

   }

La instrucción while vacía rara vez es útil y si se utiliza debe tener la siguiente forma:

   while (condition);

   // proxima instrucción aquí, dejando una linea en blanco


Nombres

La utilización de una convenciones en los nombres hace que los programas sean más legibles y fáciles de entender por otros.

Cada nombre comienza con la primera letra de cada palabra con mayúscula excepto los nombres de los campos, variables y argumentos de métodos en los cuales la primera letra de la primera palabra comienza con minúscula y la primera letra del resto de las palabras con mayúscula.

Evitar el uso _ (underscore) como separador en los nombres, para separar las palabras utilizar la primera letra de la palabra en mayúscula.


Abreviaturas

Esta sección tiene el objetivo de definir las abreviaturas a utilizar en los nombres. Las abreviaturas son una forma equivalente del nombre, no representan su tipo y no es una variante de una notación húngara. Su objetivo es reducir los nombres comunes de una forma consistente.

Por ejemplo, la abreviatura para DataReader es rdr. Así una variable que tiene los resultados de la ejecución de un comando de ADO.NET puede llamarse rdrData, dataRdr, o simplemente rdr. Todas las formas son equivalentes, aquí rdr solo define una abreviatura para DataReader, no el tipo de la variable. El tipo especifico puede ser un SqlDateReader, OleDbDataReader o algún otro tipo definido, pero que semánticamente representa un lector de datos.

Normalmente se puede utilizar solo la abreviatura en variables locales, como muestra el siguiente código:

   double tmp; // tmp = Temporal

   // ...

   if (tmp > 100)                     // tmp = Temporal

   {

      btnFilter.Enable = true;      // btn = Button

   }

El uso de las abreviaturas no es obligatorio, solo usarlo cuando no cree confusión y se reconozca de forma inmediata el nombre que representa, pero se debe evitar crear abreviaturas propias donde ya existe una. Solo usar la abreviatura donde utilizaría el nombre. Por convenio se debe utilizar la abreviatura al inicio, aunque no es necesario.


Windows Forms

Nombre | Abreviatura | Ejemplo
Button | btn | btnClose, closeBtn
CheackedListBox | clb | clbOptions
CheckBox | chk | chkShowInfo, showInfoCheckBox
ColorDialog | cld | cldTextColor
ComboBox | cbo | cboTableFields, tableFieldsCbo
ContextMenu | cmn | cmnCurrent
CrystalReportViewer | cry | cryMain
DataGrid | grd | grdResult
DateTimePicker | dtp | dtpLoad, dtp
Dialog | dlg | dlgOpenConfiguration, dlg
DomainUpDown | dud | dudRange
ErrorProvider | erp | erpGeneral
FolderBrowserDialog | fbd | fbdUserFolder
FontDialog | fnd | fndCurrentFont
Form | frm | frmAddFile, addFileForm
GrupoBox | grb | grbOptions
HelpProvider | hlp | hlpThis
HScrollBar | hsb | hsbLeftRight
Icon | ico | icoSmall
Image | img | imgIcon, iconImage
ImageList | ils | ilsIcons
Label | lbl | lblCaption
LinkLabel | lkl | lklSite
ListBox | lst | lstNames
ListVew | lvw | lvwHeadings
MainMenu | mnu | mnuFileOpen
MonthCalendar | mth | mthCurrent
NotifyIcon | nin | ninError, errorIcon
NumericUpDown | nud | nudValue
OpenFileDialog | ofd | ofdDbPath
PageSetupDialog | psd | psdGeneral
Panel | pnl | pnlLeft
PictureBox | pic | picVGA, myPictureBox, myPic
PringDialog | prd | prdMain
PrintDocument | pdc | pdcGeneral
PrintPreviewControl | ppc | ppcMain
PrintPreviewDialog | ppd | ppdMain
ProgressBar | prb | prbProcess
RadioButton | opt | optAutomaticGeneration
RichTextBox | rxt | rxtEditor
SaveFileDialog | sfd | sfdDgnFile
Splitter | spl | splVertical
StatusBar | stb | stbMain, mainStatusBar
TabControl | tab | tabOptions
TextBox | txt | txtName, passwordTxt
Timer | tmr | tmrAlarm
ToolBar | tlb | tlbEdit, editToolBar
ToolTip | ttp | ttpName
TrackBar | tkb | tkbVolume
TreeView | tvw | tvwOrganization
VScrollBar | vsb | vsbUpDown


ADO

Solution Development Kit
Convenciones para escribir código .NET
Página de inicio | solucion.biz

ADO.NET

Nombre | Abreviatura | Ejemplo
Command | cmd | cmdUpdateMovie
Connection | cnn | cnnPID
DataAdapter | dad | dadEmployer
DataColumn | dcl | dclName
DataReader | rdr | rdrEmployers
DataRelation | drl | drlUserToComputer
DataRow | drw | drwCurrent
DataSet | dst | dstInvoice
DataTable | tbl | tblPipes, pipesTable
DataView | dvw | dvwOrder
Field | fld | fldTarget, geometryField
Parameter | prm | prmId, prm
Query | qry | qry, qryLayerByName
StoreProcedure | stp | stpInsertPerson
Stream | stm | stm, stmPersons
Transaction | trn | trn


Campos

El nombre de un campo tiene la primera letra de la primera palabra en minúscula, y la primera letra del resto de las palabras en mayúscula.

El nombre debe ser corto pero con significado. No se deben usar nombres de campo de una sola letra. Solo debe usarse en casos en los que el uso de la variable sea convencional, como en el caso de una coordenada x en el plano, en este caso, su campo puede llamarse x.

Defina los campos como privados, si es necesario obtener o establecer su valor desde fuera defina propiedades o métodos con el ámbito requerido.

   private int x;

   private string lastName;


Clases

El nombre de una clase debe ser un sustantivo descriptivo, no muy largo, comenzando la primera letra de cada palabra con mayúscula. Trate de mantener el nombre sencillo y descriptivo. Use palabras completas, evite acrónimos y abreviaciones a menos que estos sean más conocidos que los nombres completos, como URL.

Siempre defina una clase dentro de un espacio de nombre.

   public class Polygon

   public class Person

   public class DgnFile


Constantes

El nombre de una constante debe ser un sustantivo o secuencia de una o más palabras, acrónimos o abreviaciones, comenzando la primera letra de cada palabra con mayúscula.

Definir las constantes con const o readonly. Un grupo de constantes que representan alternativas deben tener un prefijo común.

   private const int MinWidth = 4;

   private const int MaxWidth = 999;

   public static readonly Color Black = new Color(0, 0, 0);


Enumeraciones

El nombre de una enumeración debe comenzar con la primera letra de cada palabra en mayúscula. Utilice el mismo estilo para los valores.

Nunca utilice el sufijo Enum.

Utilice un nombre en singular para la mayoría de los tipos de enumeraciones, pero utilice un nombre en plural para los tipos enumeraciones que son campos de bits. Agregue siempre FlagsAttribute a un tipo de enumeraciones de campo de bits.

   public enum InvoiceState

   {

        Invalid = 0,

        Inprocess = 1,

        Unpaid = 2,

        Paid = 3,

        Canceled = 4

   }


Espacios de nombres

El nombre de un espacio de nombres debe comenzar con la primera letra de cada palabra en mayúscula. Se pueden anidar más niveles en los espacios de nombres. El espacio de nombres raíz de los productos desarrollados por solucion.biz es Bizion. Se debe definir al menos un espacio de nombres para cada producto o tecnología. Un espacio de nombres anidado debe tener una dependencia en los tipos del espacio de nombres contenedor.

Utilice los nombres de espacios de nombres en plural, siempre que sea correcto semánticamente. Por ejemplo, utilice Bizion.Controls en vez de Bizion.Control. Las excepciones a esta regla son los nombres y abreviaturas de marcas. Por ejemplo, Bizion.UI en vez de Bizion.UIs.

No utilice el mismo nombre para un espacio de nombres y para una clase. Por ejemplo, no proporcione un espacio de nombres Dgn y una clase Dgn.

Tenga en cuenta que el nombre de un espacio de nombres no tiene que ser igual al nombre de un ensamblado, son conceptos totalmente diferentes.

   namespace Bizion

   namespace Bizion.Dgn


Estructuras

El nombre de una estructura sigue las mismas reglas que el nombre de una clase.

Siempre defina una estructura dentro de un espacio de nombre.

   public struc DgnHeader

   public struc Point


Eventos

Utilice un sufijo EventHandler en nombres de delegados que se utilizan para implementar los eventos.

Especifique dos parámetros en el delegado denominados sender y e. El parámetro sender representa al objeto que produjo el evento. Tenga en cuenta que el parámetro sender es siempre de tipo object aunque sea posible utilizar un tipo más específico. El estado asociado con el evento está encapsulado en una instancia de una clase de eventos denominada e. Use una clase de eventos apropiada y específica para el tipo de parámetro e. Asigne un nombre a la clase de argumentos del evento con el sufijo EventArgs.

Es conveniente asignar los nombres de eventos con un verbo. Por ejemplo, nombres de eventos correctos incluyen Clicked, Painting y DroppedDown.

Utilice un verbo en gerundio para crear un nombre de evento que exprese el concepto de evento anterior, y un tiempo en pasado para representar un evento posterior. Por ejemplo, un evento Close que se puede cancelar, debe tener un evento Closing y un evento Closed. También puede utilizar un prefijo en tiempo presente o pasado, como ControlAdd o ControlAdded. No utilice el modelo de nomenclatura Before Xxx/After Xxx.

No utilice prefijo ni sufijo en la declaración de evento en el tipo. Por ejemplo, utilice Close en vez de OnClose.

En general, se debe proporcionar un método protegido virtual denominado On EventName en los tipos con eventos que se pueden reemplazar en una clase derivada. Este método debe tener sólo el parámetro de evento e, ya que el remitente es siempre la instancia del tipo. Este método permite a las clases derivadas controlar el evento sin asociar un delegado y es el que invoca el evento llamando a los delegados.

   // delegado

   public delegate void MouseEventHandler(object sender, MouseEventArgs e);

   // evento

   public event MouseEventHandler MouseMove;

   // metodo que genera el evento

   protected virtual void OnMouseMove(MouseEventArgs e)

   {

        ...

     }

   // metodo que se invoca al generar el evento

   private void x_MouseMove(object sender, MouseEventArgs e)

   {

        ...

     }


Interfaces

El nombre de una interfaz sigue las mismas reglas que el nombre de una clase, excepto que debe comenzar con el prefijo I.

Siempre defina una interfaz dentro de un espacio de nombre.

   public interface IWizardSite;

   public interface IBackgroundProcess;


Métodos

El nombre de un método debe ser un verbo o una frase verbal, con la primera letra en mayúscula, y la primera letra de cada palabra siguiente en mayúscula.

Si el método obtiene o establece algún valor utilice los prefijos Get Value o Set Value. Antes de utilizar métodos Get Value o Set Value compruebe que no es mejor utilizar una propiedad con nombre Value.

Si un método prueba la veracidad de alguna condición debe llamarse Is Condition.

   public void RunFast();

   private Color GetBackground();

   protected bool IsInrerrupted();


Propiedades

Utilice un sustantivo o un sintagma nominal al asignar nombres a las propiedades, con la primera letra en mayúscula, y la primera letra de cada palabra siguiente en mayúscula.

Es conveniente crear una propiedad con el mismo nombre que el tipo subyacente correspondiente. Por ejemplo, si declara una propiedad con el nombre Color, el tipo de propiedad también deberá llamarse Color.

   public Color BackColor

   {

        get

        {

           // opcional si es de solo escritura

        }

        set

        {

           // opcional si es de solo lectura

        }

   }


Variables

El nombre de una variable tiene la primera letra de la primera palabra en minúscula, y la primera letra del resto de las palabras en mayúscula.

El nombre debe ser corto pero con significado, puede usarse algún nemotécnico para variables locales a los métodos. No se debe utilizar ningún tipo de notación húngara.

Variables de una sola letra deben evitarse, solo usarse en casos en los que el uso de la variable sea efímero, como en el caso de una excepción, o estándar, como en el índice de un ciclo. Siempre que se pueda y contribuya a la claridad, para una variable que representa una instancia de una clase X utilizar el nombre x.

// variable en un método a que es miembro de una clase

   int pos;

   float myWidth;

   Thread aThread;

   Person employer;

// nombres estándar de una sola letra

   byte b;

   char c;

   double d;

   Exception e;

   float f;

   int i,j,k;

   long l;

   object o;

   string s;


Practicas de programación

Esta sección incluye consejos generales al programar en C#.


Distinción entre mayúsculas y minúsculas

Para evitar confusiones y garantizar la interoperación entre lenguajes, siga estas reglas con respecto a la distinción entre mayúsculas y minúsculas:

· No utilice nombres públicos o protegidos que requieran distinción entre mayúsculas y minúsculas. Los componentes se deben poder utilizar en los lenguajes que distinguen, y en los que no distinguen, entre mayúsculas y minúsculas. Los lenguajes que no hacen esta distinción no pueden diferenciar, dentro del mismo contexto, dos nombres que difieren sólo en el uso de mayúsculas y minúsculas. Por consiguiente, se debe evitar esta situación en los componentes o clases creados.

· No debe crear dos espacios de nombres con nombres que difieran sólo en las mayúsculas y minúsculas. Por ejemplo, un lenguaje que no haga distinción entre mayúsculas y minúsculas no distingue entre las dos declaraciones siguientes de espacio de nombres.

        namespace ee.cummings;

        namespace Ee.Cummings;

· No debe crear una función con nombres de parámetros que difieran sólo en las mayúsculas y minúsculas. El siguiente ejemplo es incorrecto.

        void MyFunction(string a, string A)

· No cree un espacio de nombres con nombres de tipos que difieran sólo en las mayúsculas y minúsculas. En el siguiente ejemplo, Point p y POINT p son nombres de tipo incorrectos ya que difieren sólo en el uso de las mayúsculas y minúsculas.

        System.Windows.Forms.Point p

        System.Windows.Forms.POINT p

· No debe crear un tipo con nombres de propiedades que difieran sólo en las mayúsculas y minúsculas. En el siguiente ejemplo, int Color y int COLOR son nombres de propiedades incorrectos ya que difieren sólo en el uso de las mayúsculas y minúsculas.

        int Color {get, set}

        int COLOR {get, set}

· No debe crear un tipo con nombres de métodos que difieran sólo en las mayúsculas y minúsculas. En el siguiente ejemplo, calculate y Calculate son nombres de métodos incorrectos ya que difieren sólo en el uso de las mayúsculas y minúsculas.

        void calculate()

        void Calculate()


Uso de las funciones de devolución de llamada

Los delegados, las interfaces y los eventos permiten proporcionar la funcionalidad de devolución de llamada. Cada tipo tiene sus propias características de uso que se adaptan perfectamente a situaciones específicas.

Eventos

Utilice un evento si se cumplen las siguientes condiciones:

· Un método solicita por adelantado la función de devolución de llamada, normalmente, a través de métodos Add (+=) y Remove (-=) distintos.

· Normalmente, hay más de un objeto que requiere la notificación del evento.

· Desea que los usuarios finales puedan agregar fácilmente un agente de escucha a la notificación en el diseñador visual.

Delegados

Utilice un delegado si se cumplen las siguientes condiciones:

· Desea un puntero a función con estilo de lenguaje C.

· Desea una función de devolución de llamada sencilla.

· Desea que el registro se produzca en la llamada o durante la construcción y no a través de un método Add (+=) distinto.

Interfaces

Utilice una interfaz si la función de devolución de llamada requiere un comportamiento complejo.


Eventos y delegados

Un evento es un mensaje que envía un objeto cuando ocurre una acción. La acción puede estar causada por la interacción del usuario, como un clic, o por otra lógica del programa. El objeto que provoca (desencadena) el evento se denomina remitente del evento. El objeto que captura el evento y responde a él se denomina receptor del evento.

En las comunicaciones de eventos, el remitente del evento no sabe qué objeto o método recibirá los eventos que provoca. Se necesita un intermediario (o mecanismo de tipo puntero) entre el origen y el receptor. Se define un tipo especial llamado delegado que proporciona la funcionalidad de un puntero a función.

Un delegado es una clase que puede guardar una referencia a un método. A diferencia de otras clases, una clase de delegado tiene un prototipo y puede guardar referencias únicamente a los métodos que coinciden con su prototipo. Por lo tanto, un delegado equivale a un puntero a función con seguridad o a una devolución de llamada. Aunque los delegados tienen otros usos, esta explicación se centra en la funcionalidad de control de eventos de los delegados.

En el siguiente ejemplo se muestra la declaración de un delegado de eventos llamado AlarmEventHandler:

   public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);

Por convención, los delegados de evento tienen dos parámetros, el origen que provocó el evento (sender) y los datos del evento (e).

Una declaración de delegado es suficiente para definir una clase de delegado. La declaración proporciona el prototipo del delegado y CLR proporciona la implementación.

Una clase puede incluir la siguiente declaración de evento Alarm, que utiliza el delegado AlarmEventHandler:

   public class Clock

     {

        public event AlarmEventHandler Alarm;

        // esto es opcional, pero recomendado

        protected virtual void OnAlarm(AlarmEventArgs e)

        {

           if (Alarm != null)

           {

             Alarm(this, e);

           }

        }

   }

Cuando el compilador encuentra la palabra clave event genera un campo privado para el delegado y dos métodos para agregar y quitar delegados. Se puede utilizar otra forma de definición de eventos (add, remove) si desea controlar la forma en que se almacenas e invocan los delegados.

El método virtual protegido OnAlarm es el que provoca el evento invocando a los delegados. Este método también permite que las clases derivadas reemplacen el evento sin asociar un delegado. Una clase derivada siempre debe llamar al método On EventName de la clase base para asegurarse de que los delegados registrados reciben el evento.

Una instancia del delegado AlarmEventHandler puede enlazarse a cualquier método que coincida con su prototipo, como el método AlarmRang de la clase WakeMeUp:

   public class WakeMeUp

   {

        public void AlarmRang(object sender, AlarmEventArgs e)

     }

Para conectar el método AlarmRang de la clase WakeMeUp al evento Alarm de la clase Clock tiene que crear una instancia del delegado AlarmEventHandler que tome una referencia del método AlarmRang de una instancia WakeMeUp y lo registre en el evento Alarm de una instancia Clock:

   clock.Alarm += new AlarmEventHandler(wakeMeUp.AlarmRang);

Los delegados de evento son de multidifusión, lo que significa que pueden guardar referencias a más de un método de control de eventos. Los delegados permiten realizar un control de eventos más flexible y detallado. Un delegado actúa como remitente de eventos de la clase que provoca el evento y mantiene una lista de los controladores registrados para el evento.


Liberar recursos no administrados

A menudo, las instancias de clases encapsulan el control sobre los recursos que no administra el motor de tiempo de ejecución, como identificadores de ventanas (HWND), conexiones a bases de datos, etc. Por consiguiente, deberá proporcionar las formas explícita e implícita de liberar esos recursos.

Proporcione el control implícito implementando el destructor de C#. El recolector de elementos no utilizados llama al destructor en algún momento, cuando ya no hay ninguna referencia válida al objeto.

Nota: El destructor de C# es equivalente al método Finalize de otros lenguajes.

En algunos casos, se puede proporcionar a los programadores la utilización de un objeto con capacidad para liberar explícitamente estos recursos externos, antes de que el recolector de elementos no utilizados libere el objeto. Si el recurso externo es insuficiente o resulta muy caro, se puede conseguir un mejor rendimiento si el programador libera explícitamente los recursos cuando ya no se utilizan. Para proporcionar el control explícito, se implementa el método Dispose que proporciona la interfaz IDisposable. El consumidor del objeto deberá llamar a este método una vez halla terminado de utilizar el objeto. Se puede llamar al método Dispose aunque todavía existan referencias al objeto.

Nota: En C# se puede utilizar la instrucción using para llamar automáticamente al método Dispose.

Hay que tener en cuenta que cuando se proporciona el control explícito mediante el método Dispose, se debe proporcionar la limpieza implícita utilizando el destructor. El destructor proporciona una copia de seguridad para evitar que los recursos se pierdan permanentemente si el programador no llama al método Dispose.


Uso de paréntesis

En general es buena idea utilizar paréntesis en expresiones que involucran distintos tipos de operadores para evitar problemas de precedencia. Si la precedencia de los operadores esta clara para usted, pudiera ser que otros no la tuvieran tan clara.

   if (a == b && c == d) // EVITAR!

   if ((a == b) && (c == d)) // OK


Valores de retorno

Trate de que la estructura del código concuerde con su propósito, por ejemplo:

   if (booleanExpression)

   {

     return true;

   }

   else

   {

     return false;

   }

Debería ser escrito como:

   return booleanExpression;

Similarmente:

   if (condition)

   {

     return x;

   }

   return y;

Debería ser escrito como:

   return (condition ? x : y);

   // SI NO QUEDA CLARO, ESCRIBIRLO ASI

   if (condition)

   {

     return x;

   }

   else

   {

     return y;

   }


Definir constantes

Al definir constantes de tipo entero, compruebe que no se pueden representar mejor como una enumeración.

   public const int Error      = 1; // EVITAR!!!

   public const int Information = 2; // EVITAR!!!

   public enum ValuesName

   {

        Error        = 1;          // ES PREFERIBLE

        Information = 2;

   }

Si accede a las constantes, campos o métodos de los tipos básicos utilice su estructura y no la palabra clave equivalente.

   string.Empty; // EVITAR!!!

   String.Empty;                 // ES PREFERIBLE

   double.MinValue;                 // EVITAR!!!

   Double.MinValue;                 // ES PREFERIBLE

   double.Parse(str);            // EVITAR!!!

   Double.Parse(str);            // ES PREFERIBLE

Si necesita utilizar cadenas que no son localizables, por ejemplo, nombre de valores de configuración, defina una constante publica con su valor y evite codificarla directamente. Puede definir estas constantes en la clase que la utiliza o definir una clase sellada con constructor privado que incluya las constantes si estas se utilizan por más de una clase.

public const string CurrentCultureName = "CurrentCultureName";

Evite utilizar la cadena vacía directamente, es preferible utilizar String.Empty.

   return ""; // EVITAR!!!

   return String.Empty;             // ES PREFERIBLE


Asignación de variables

Evite asignar a varias variables el mismo valor en la misma instrucción, esto es difícil de leer. Tampoco use asignaciones anidadas en expresiones buscando eficiencia, eso es trabajo del compilador.

   fooBar.Char = barFoo.Char = 'c';   // EVITAR!!!

   d = (a = b + c) + r;               // EVITAR!!!

   a = b + c;                         // LO ANTERIOR ESCRIBIRLO ASI

   d = a + r;


Fomentar la reutilización

Cree módulos y clases cohesivos y débilmente acoplados. Por acoplamiento se entiende la medida de la fuerza de la asociación establecida por una conexión entre un módulo o clase con otro. El acoplamiento fuerte complica un sistema porque los módulos o clases son más difíciles de comprender, cambiar o corregir por sí mismos si están muy interrelacionados con otros módulos o clases.

La cohesión mide el grado de conectividad entre los elementos de un solo módulo o clase. Se deben crear clases o módulos donde sus elementos trabajan juntos para proporcionar algún comportamiento bien delimitado.

Los módulos y clases también deben ser suficientes, completos y primitivos. Por suficientes se quiere decir que la clase o modulo captura suficientes características de la abstracción como para permitir una interacción significativa y eficiente. Por completo, quiere decir que la interfaz de la clase o módulo captura todas las características significativas de la abstracción, mientras que suficiente implica una interfaz mínima, una interfaz completa es aquella que cubre todos los aspectos de la abstracción.

Defina métodos que realizan una sola operación basada en sus argumentos y estado interno. Siempre trate de minimizar el número de argumentos de un método.


Manejo de excepciones

Utilice el mecanismo de excepciones para controlar las situaciones de error.

Siempre proteja un manipulador de evento de interfaz de usuario con una instrucción try-catch, esto evita que una excepción termine con la aplicación, o que se muestre una información poco amigable al usuario.

Utilice un bloque finally para liberar los recursos obtenidos y que se tienen que liberar ocurra o no una excepción.

Por cada producto defina una clase que herede de System.ApplicationException para el manejo de excepciones especificas a la aplicación.

Cuando genere una excepción con la instrucción throw utilice la clase de excepción especifica de la aplicación con información relevante al usuario. Por ejemplo, si en la manipulación de datos ocurre una excepción del tipo InvalidConstraintException capture esta excepción y genere una nueva que explique que relación viola la restricción.


Globalizar y localizar

La globalización es el proceso mediante el cual se diseñan y desarrollan productos de software que pueden funcionar para varias referencias culturales.

La localización es el proceso mediante el cual se personaliza una aplicación para una referencia cultural o configuración regional determinadas. La localización consiste principalmente en la traducción de la interfaz de usuario.

Las propiedades CurrentCulture y CurrentUICulture definen las referencias culturales que una aplicación utiliza para determinar qué recursos se cargan para una aplicación y cómo se da formato las monedas, los números y las fechas. Los recursos que se cargan vienen determinados por el valor de CurrentUICulture, mientras que las opciones de formato las determina el valor de CurrentCulture.

Estas propiedades pertenecen al subproceso actual y por defecto toman valor desde la configuración del sistema. El valor de CurrentCulture tiene que ser una referencia cultural especifica y el valor de CurrentUICulture puede que ser una referencia cultural neutral o especifica.

Utilice la propiedad InvariantCulture de la clase CultureInfo para asegurarse de que el comportamiento será uniforme independientemente de la configuración regional del sistema. No obstante, la referencia cultural invariable sólo debe ser utilizada cuando se requieran resultados independientes de la referencia cultural, en caso contrario, producirá resultados que podrían ser lingüísticamente incorrectos o culturalmente inadecuados.


Globalizar

La globalización es el proceso de diseño y desarrollo de un producto de software que pueda funcionar con diversas culturas o configuraciones regionales, se deben tener en cuenta las siguientes áreas en la globalización:

§ Clasificación de caracteres

§ Formato de fecha y hora

§ Convenciones numéricas, monetarias, de pesos y de medidas

§ Reglas de ordenación

Para soportar la globalización se deben incluir el espacio de nombres System.Globalization y utilizar sus clases.

No se deben utilizar cadenas directamente en el código, en su lugar localizar siempre las cadenas mediante una nombre invariante en ingles. Por ejemplo, si se debe mostrar un mensaje al usuario, en el código se hará referencia a esta cadena como con el nombre UserMessage y se utilizaran dos métodos Localize (de objeto) y LocalizeText (de clase) para obtener la cadena localizada. Por ejemplo:

MessageBox.Show(this, Localize("UserMessage", ""), Localize("Caption"));

El método Localize es un método de objeto que recibe una cadena a localizar y un número variable de argumentos que se agregan a la cadena, a continuación se muestra la signatura y una implementación básica de este método.

/// <summary>

/// Localiza una cadena según la configuración cultura actual.

/// </summary>

/// <remarks>

/// Si no se encuentra la cadena localizada se obtiene la cadena pasada en

/// el parámetro <paramref name="s"/>.

/// </remarks>

/// <param name="s">Cadena a localizar.</param>

/// <param name="v">Matriz de objetos a los que se le aplicara el formato.</param>

/// <returns>Cadena localizada según la configuración cultural actual.</returns>

protected virtual string Localize(string s, params object[] v)

{

   ResourceManager rm = new ResourceManager("Strings", this.GetType().Assembly);

   string ls = rm.GetString(s);

   if (ls == null)

   {

        Debug.WriteLine("Can´t localize string '" + s + "'");

        return s;

   }

   else

   {

        return String.Format(ls, v);

   }

}

El método LocalizeText es un método de clase que tiene la misma signatura que el método Localize.

/// <summary>

/// Localiza una cadena según la configuración cultura actual.

/// </summary>

/// <remarks>

/// Si no se encuentra la cadena localizada se obtiene la cadena pasada en

/// el parámetro <paramref name="s"/>.

/// </remarks>

/// <param name="s">Cadena a localizar.</param>

/// <param name="v">Matriz de objetos a los que se le aplicara el formato.</param>

/// <returns>Cadena localizada según la configuración cultural actual.</returns>

protected static string LocalizeText(string s, params object[] v)


Localizar

La localización es el proceso que permite adaptar una aplicación globalizada a una cultura o configuración regional determinadas. Vea la sección correspondiente a la tecnología utilizada para crear la interfaz de usuario para más información.

Debe definir la referencia cultural especifica antes de que se carguen los recursos específicos, un buen lugar para esto es cuando el usuario inicia la sesión en la aplicación. Puede obtener la referencia cultural para el usuario desde un valor de configuración en el archivo de configuración de la aplicación, como se muestra a continuación.

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

   <appSettings>

     <add key="CurrentCultureName" value="es" />

   </appSettings>

</configuration>

Al iniciar la sesión se puede utilizar el siguiente código para establecer la referencia cultural actual.

string userCultureName = ConfigurationSettings.AppSettings["CurrentCultureName"];

if (userCultureName != null)

{

   Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(userCultureName);

   Thread.CurrentThread.CurrentUICulture = new CultureInfo(userCultureName);

}


Interfaz de usuario

Esta sección incluye consejos sobre el diseño de la interfaz de usuario.


Escribiendo textos en la interfaz de usuario

Las palabras que se utilizan en la interfaz es una forma primaria de comunicación con el usuario. Esta sección brinda algunas guías para la redacción efectiva de los textos de interfaz.


Abreviaturas

Evite las abreviaturas, excepto en el caso de que la abreviatura sea tan conocida por el usuario como la frase completa. Si usa abreviaturas, siga las siguientes reglas:

· Siempre utilice la frase completa la primera vez que aparezca en cualquier parte de la interfaz de usuario e incluya seguido la abreviatura entre paréntesis. Muestre la abreviatura en las apariciones subsiguientes dentro del mismo formulario, en paginas subsiguientes de un asistente o en formularios anidados a las que el usuario solo puede llegar luego de haber pasado por el formulario que mostró la frase completa.

· Evite usar las abreviaturas en los títulos.


Teclas de acceso directo

Siempre defina teclas de acceso directo para los controles o los elementos de menú. La única excepción en este caso son los botones de Aceptar y Cancelar, para los cuales las teclas ESC y ENTER le sirven como teclas de acceso directo. También, evite usar las mismas teclas de acceso directo para distintos controles en un mismo contexto o para más de un elemento en el mismo menú.


Acrónimos

Use los acrónimos para los términos que no sean marcas comerciales o para estándares bien conocidos de la industria. Para los acrónimos mas conocidos no hay necesidad de poner las frases completas. Para otros menos conocidos se puede utilizar la misma regla que para las abreviaturas, excepto que si la primera aparición del acrónimo es en un título se debe poner el acrónimo y considerar la próxima aparición como la primera y en ese lugar poner la frase completa seguida del acrónimo encerrado entre paréntesis.


Capitalización

Una correcta capitalización ayuda a los usuarios a identificar palabras o frases importantes. Existen dos tipos de capitalización, la capitalización de títulos y la capitalización de oraciones.

La capitalización de títulos pone en mayúsculas todas las palabras de la frase, exceptuando artículos (el, la, etc.), conjunciones (con, y, para, etc.) y preposiciones de 4 o menos letras (en, para, con, etc.).

La capitalización de oraciones pone en mayúsculas solamente la primera palabra de la frase.

Se utilizara siempre que sea posible la capitalización de oraciones.


Puntos suspensivos

Si un acción requiere información adicional para ser completada y se utilizara la interfaz de usuario para suministrar esa información, utilice los puntos suspensivos (...) seguido del texto de la acción. De esa manera el usuario tiene una pista de que acciones requieren información extra.

Por ejemplo: la acción Guardar como....


Texto de instrucción

Utilice los textos de instrucción en formularios y páginas de asistentes para brindar información adicional acerca de la tarea que el usuario desea acometer.

El texto puede incluir una descripción general e información especifica.


Puntuación

Siga las reglas normales de puntuación para los textos de la interfaz de usuario. Encierre las preguntas entre signos de interrogación, evite poner las etiquetas de los controles como preguntas. Separe las oraciones con un espacio en blanco.

En una lista numerada o con viñetas, introduzca la lista con una oración terminada en dos puntos (:). Comience cada entrada de la lista en mayúsculas y termínelas con el punto.

Las entradas en una lista deben ser paralelas (tener la misma estructura gramatical).


Estilo de redacción

El estilo de la redacción depende de la formación de los usuarios. No se escribe de la misma manera los textos para una interfaz para usuarios novatos que para administradores de sistemas. Debe investigar cual es la formación de los usuarios antes de comenzar a crear la interfaz. El estilo se conforma de varios factores, de los cuales depende la legibilidad y comprensión de la interfaz de usuario.

Mantenga los textos en la interfaz de usuario lo más breves posible. Los estudios de usabilidad indican que los usuarios son propensos a leer los bloques cortos de textos y evitar los largos.

· Focalice los textos en lo que el usuario debe conocer.

· Use palabras y frases directas.

· Use verbos específicos y descriptivos, evite el uso de verbos como hacer, procesar, etc., en su lugar utilice mostrar, importar, etc.

· Evite las frases que no aportan información: mas o menos, básicamente, realmente, etc.

· Escriba oraciones positivas. Evite el uso de palabras como: malo, error o falla. En su lugar, dígale al usuario cual es el problema, qué hacer y por qué.

· Evite las redundancias: exactamente igual, absolutamente completo, repita de nuevo, todos y cada uno, etc.

· Use frases consistentes en condiciones similares. De esta manera el usuario no asume que han cambiado las condiciones por el cambio en las frases.

· Use el plural siempre para asumir el singular. No use (s) después de los sustantivos. Por ejemplo: ponga Archivos y no Archivo(s).


Construcción paralela

Use la misma estructura gramatical para frases que dan el mismo tipo de información. Por ejemplo: lista de opciones, listas de elementos, etc.

A continuación se muestran un conjunto de ejemplos:

Formas correctas:

Obtenga información actualizada acerca de actualizaciones y nuevos productos; Use Actualización automática para descargarlas actualizaciones de los productos.

Forma incorrecta:

Información actualizada acerca de actualizaciones y nuevos productos le será enviada; Usando Actualización automática puede descargar las actualizaciones de los productos.

Use oraciones en la interfaz de usuario para explicar conceptos, introducir características, etc. Las oraciones deben ser simples y cortas. Si la oración es muy larga divídala en oraciones más cortas. Use listas o tablas para dividir oraciones.

Use el tiempo presente, por ejemplo:

La aplicación no puede encontrar el archivo.

no utilice:

La aplicación no pudo encontrar el archivo.

Escriba oraciones afirmativas, diciéndole al usuario que hacer, en vez de decirle que no hacer, por ejemplo:

Para reiniciar el sistema presione Reiniciar.

no utilice:

No presione CTRL+ALT+DEL para reiniciar el sistema.

Cuando una oración describe una secuencia de acciones, escríbala en el orden en que las acciones deben ser realizadas, por ejemplo:

Reinstale el programa y reinicie el sistema.

no utilice:

Reinicie el sistema después de reinstalar el programa.

Evite utilizar un control dentro de una frase si esta puede ser internacionalizada. En su lugar, colóquelo al final de la frase, por ejemplo:

Número de conexiones concurrentes por servidor: N

no utilice:

Existen N conexiones concurrentes por servidor.


Títulos comunes

Utilice las siguientes palabras como titulo siempre que sea posible:

Título | Descripción
Aceptar | Cierra el formulario y acepta los cambios.
Cancelar | Cierra el formulario y cancela los cambios.
Aplicar | Aplicar cambios en opciones o propiedades. No modifica el estado de visualización del formulario.
Agregar | Agregar objetos que existen a un conjunto, su opuesto es Quitar.
Quitar | Quitar objetos de un conjunto, objeto sigue existiendo, su opuesto es Agregar.
Nuevo | Crea un objeto a un conjunto, el objeto no existe hasta que se crea, semánticamente el objeto solo puede existir en el conjunto, su opuesto es Eliminar.
Eliminar | Elimina un objeto de un conjunto, el objeto es destruido cuando es eliminado del conjunto, su opuesto es Nuevo.
Modificar | Modificar el objeto seleccionado, quizás mostrando su formulario de propiedades.
Propiedades | Muestra el formulario de propiedades del objeto seleccionado.
Cerrar | Cierra el formulario.
Detalle | Muestra más información sobre algo.
Actualizar | Refresca los datos de la interfaz de usuario.
Buscar | Realiza una búsqueda, quizás mostrando un formulario de búsqueda.


Diseñando la interfaz de usuario

El tamaño, espaciado y ubicación de la información son aspectos críticos en la creación de un entorno visualmente consistente y predecible.

Esta sección incluye las guiás a seguir según la tecnología utilizada.


Windows Forms

Esta sección incluye la guías para crear la interfaz de usuario en aplicaciones Windows Forms.


Globalizar

Para soportar aplicaciones Windows Forms internacionales sigua las siguientes directrices:

§ Asigne valores según la referencia cultural al usuario a las propiedades CurrentCulture y CurrentUICulture del subproceso actual.

§ Asigne el valor de True a la propiedad Localizable de los formularios. Esta propiedad hay que establecerla antes de agregar controles y diseñar la interfaz de usuario, los controles agregados antes de poner esta propiedad puede que no sean visibles.

§ Defina la interfaz de usuario para cada una de las referencias culturales soportadas, en los formularios asigne el valor correspondiente al lenguaje en la propiedad Language. El valor por defecto (predeterminado) se utilizara cuando no se encuentre un recurso para la referencia cultural especifica.

§ Agregue un archivo de recursos de ensamblado para las cadenas a localizar, se sugiere el nombre de archivos Strings.resx, este archivo contendrá las cadenas para la referencia cultural por defecto (predeterminada). Agregue un archivo de recursos de ensamblado para cada una de las referencias culturales soportadas, el nombre del recurso debe ser igual al recurso de la referencia cultural predeterminada agregándolo el nombre de la referencia cultural neutral, por ejemplo, para ingles seria Strings.en.resx y para catalán Strings.ca.resx.

Para eliminar la localización de un formulario en una referencia cultural especifica se debe eliminar su respectivo archivo de recurso. Para esto, en el Explorador de soluciones compruebe que la opción mostrar todos los archivos esta activa, expanda el formulario y borre el archivo de recurso de ensamblado (archivo con extensión resx) para la referencia cultural especifica.


Tamaño

La siguiente tabla tiene los tamaños estándares para los controles:

Control | Ancho (píxeles) | Alto (píxeles)
Button | 80 | 24
ComboBox | 96 o 288, 168 | 20
CheckBox | 96 o 288 | 20
TextBox | 96 o 288, 168 | 20
RadioButton | 96 o 288 | 20
PictureBox | 16 o 32 | 16 o 32
ListView | 376 |
TreeView |  |
Label | 88 | 20 o 32

Siempre verifique que los formularios caben completamente en la pantalla con resolución 800x600 píxeles, si es posible también en 640 x 480 píxeles.

Mantenga el ancho de los botones consistente para garantizar la legibilidad, aunque en algunos casos puede ser necesario que un botón sea más ancho que el resto.


Márgenes

Mantenga un margen consistente con respecto a los bordes del formulario y paneles. Se recomienda utilizar como margen el doble del ancho de la cuadricula de 8 píxeles, es decir 16 píxeles, o múltiplos de esta.