martes, 19 de enero de 2016

Atributos en C#

Existen usos muy importantes de los atributos, los cuales se aplican para seguridad, como por ejemplo validar la autorización del uso de la clase, la definición de servicios, es decir de los contratos para los servicios [ServiceContract], de los métodos de los contratos [OperationContract]; en la definición de clases para definir el modelo de datos en MVC, métodos, etc.

Estos atributos crean la metadata que se puede utilizar en el proceso de compilación, además de otros importantes usos, y de ahí su importancia el manejar estos elementos del lenguaje.

Los atributos son etiquetas declarativas, es decir información adicional. Esta información se puede recuperar en tiempo de ejecución por medio del mecanismo de reflexión. Pueden usarse atributos predefinidos o personalizarlos.

Los atributos pueden ser colocados en la mayoría de las declaraciones (aunque un atributo especifico podría estar restringido a los tipos de declaraciones). La sintaxis, define que se coloque entre paréntesis cuadrados adelante de la declaración de la entidad a la que se aplica, por ejemplo el atributo Conditional.

[Conditional("DEBUG")] public class myClaseDebug


Aplicación de los atributos
En ocasiones la aplicación de atributos puede resulta ambiguo, veamos el siguiente ejemplo

[MiAtributo] int miMetodo (string cadenaTexto)

En el ejemplo es necesario saber con certeza a quien se aplica el atributo, ya sea al método o al valor de retorno. Para resolver estas situaciones, existen elementos conocidos como "destinos" predeterminados.

Por omisión el atributo aplica al método:

[MiAtributo] int miMetodo

Puede reemplazarse por especificaciones explicitas, por ejemplo:

[method: MiAtributo ] int miMetodo
[return: OtroAtributo] int miMetodo

La sintaxis general es:

[destino: lista-de-atributos]

El destino (target), es uno de los posibles destino assembly, field, module, param, property, return o type. La lista de atributos, se refiere a los atributos a aplicar.

Declaración
Destinos posibles
assembly assembly [assembly: lista-atributos]
module module    [module: lista-atributos]
class type
struct type
interface type
enum type
delegate type, return
method method, return
parameter param
field field
property — indexer property
property — get accessor method, return
property — set accessor method, param, return
event — field event, field, method
event — property event, property
event — add method, param
event — remove method, param

Atributos Globales
La mayoria de los atributos se relacionan a elementos específicos de lenguaje, como clases o métodos; sin embargo, algunos atributos son globales - estos se aplican a un ensamblado completo o un módulo

[assembly: lista-tributos]

[module: lista-atributos]

Los atributos globales aparecen después de las declaraciones using y antes que las declaraciones de espacio de nombres o de tipo, pueden aparecer en cualquier cantidad de archivos fuente pero sólo para una compilación. Por ejemplo:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyTitle("MiAplicacion")]

Otros atributos de uso más frecuente:

AssemblyCompanyAttribute
AssemblyConfigurationAttribute
AssemblyCopyrightAttribute
AssemblyCultureAttribute
AssemblyDescriptionAttribute
AssemblyProductAttribute
AssemblyTrademarkAttribute
NOTA
En el uso cotidiano es posible retirar del nombre del atributo el sufijo Attribute sin mayor problema

Crear atributos personalizados
Es posible crear atributos personalizados creando una clase de tipo atributo, ésta se deriva directamente de System.Attribute, esto permite identificar definiciones de atributos como metadatos de forma rápida y sencilla. Enseguida un ejemplo.

using System;

namespace AtributosPersonalizados
{

 
    /// <summary>
    /// La clase crea un atributo personalizado y documenta al desarrollador que
    /// creo la clase.
    ///
    /// El uso de System.Attribute, como clase base
    /// define que se trata de un atributo personalizado.
    ///
    /// El uso de AttributeUsage, se define para validar que el atributo
    /// Desarrollador solo se usara para clases y estructuras.
    /// El parametro con nombre: AllowMultiple, permite que el atributo sea
    /// de un solo uso o multiple.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, AllowMultiple = true)]
    public class Desarrollador: Attribute
    {
        string _nombre;
        public string version;

        /// <summary>
        /// El constructor toma el nombre y define un valor
        /// por omision para la versión.
        /// </summary>
        /// <param name="nombre"></param>
        public Desarrollador(string nombre)
        {
            this._nombre = nombre;
            this.version = "1.0.0.0";
        }
    }

    // Ejemplo de la declaración de una clase con el uso del
    // atributo personalizado
    [Desarrollador("Pedro Perez", version ="2.0.0.0")]
    public class ClaseConAtributoPersonalizado
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Reflexion, recuperación de información de atributos
Esta tarea se realiza por medio del método GetCustomAttributes, el cual nos proporciona una matriz de objetos equivalentes a los atributos de código fuente, en tiempo de ejecución.

Enseguida un ejemplo del uso de del método GetCustomAttributes.
using System;

namespace AtributosPersonalizados
{

 
    /// <summary>
    /// La clase crea un atributo personalizado y documenta al desarrollador que
    /// creo la clase.
    ///
    /// El uso de System.Attribute, como clase base
    /// define que se trata de un atributo personalizado.
    ///
    /// El uso de AttributeUsage, se define para validar que el atributo
    /// Desarrollador solo se usara para clases y estructuras.
    /// El parametro con nombre: AllowMultiple, permite que el atributo sea
    /// de un solo uso o multiple.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, AllowMultiple = true)]
    public class Desarrollador: Attribute
    {
        string _nombre;
        public string version;

        /// <summary>
        /// El constructor toma el nombre y define un valor
        /// por omision para la versión.
        /// </summary>
        /// <param name="nombre"></param>
        public Desarrollador(string nombre)
        {
            this._nombre = nombre;
            this.version = "1.0.0.0";
        }


        // Obtiene el nombre del desarrollador
        public string NombreDesarrollador()
        {
            return _nombre;
        }


    }

    // Ejemplo de la declaración de una clase con el uso del
    // atributo personalizado
    [Desarrollador("Pedro Perez", version ="2.0.0.0")]
    public class ClaseConAtributoPersonalizado
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Información de la clase ClaseConAtributoPersonalizado");
            Attribute[] atributosClase = Attribute.GetCustomAttributes(typeof(ClaseConAtributoPersonalizado));
            foreach (Attribute atributo in atributosClase)
            {
                if(atributo is Desarrollador)
                {
                    Desarrollador d = (Desarrollador)atributo;
                    Console.WriteLine(" Nombre: {0}, version: {1} ", d.NombreDesarrollador(), d.version);
                }
            }
            Console.ReadKey();

        }

     

    }
}



Referencias:
https://msdn.microsoft.com/es-es/library/aa288182(v=vs.71).aspx
https://msdn.microsoft.com/es-es/library/aa287893(v=vs.71).aspx
https://msdn.microsoft.com/es-es/library/aa287991(v=vs.71).aspx






jueves, 14 de enero de 2016

Trabajando con Estructuras en C#

Uno de los tipos de datos con los que podemos trabajar en C# y que como las clases podemos personalizar son las estructuras (structs) o estructuras de datos (Data structures). Las estructuras pueden tener campos, métodos, propiedades y constructores; estos constructores tienen una limitación, no se puede declarar un constructor sin parámetros; si el constructor de la estructura tiene parámetros se puede trabajar sin mayor problema, el compilador siempre genera para las estructuras un constructor sin parámetros y coloca los campos con valores por omisión como: 0, falso o null.

La mayoría de los tipos de datos conocimos como primitivos de C# son estructuras.

Cuando usamos int, long, float, etc. utilizamos alias para  un manejo más simple de las estructuras, System.Int32, System.Int64 y System.Single. Estas estructuras tienen campos y métodos, por ejemplo el método ToString, que convierte el número en su representación en cadena.

Al usar Visual Studio podemos observar como los tipos de datos primitivos son definidos como estructuras, como se ve en la siguiente imagen.




Un importante método estático de estos tipos de datos es Parse, utilizado para convertir una cadena a su valor numérico correspondiente, por ejemplo:


En este ejemplo usamos el alias int para declarar las variables de tipo numérico.

Estas estructuras ademas tienen algunos campos de tipo estático que son útiles, por ejemplo, Int32.MaxValue que representa al máximo valor posible a almacenar en un tipo de valor int.



La siguiente tabla presenta los alias y su equivalente del .NET Framework. Observe que string y object son clases.
Declarando un estructura
Para declarar una estructura se utiliza la palabra clave struct y delante de ella el nombre de la estructura.

Es posible definir los valores de los campos, proporcionando un constructor con parámetros, ya que el compilador crea el constructor por omisión sin parámetros. En una estructura no esa permitido colocar valores por omisión a los campos. Los campos definidos como estáticos tienen permitido colocar valores por omisión.

Si quiere copiar una estructura no inicializada el compilador no lo permite.

El GC (Garbage Collector) recupera la memoria usada para la declaración del tipo, de forma inmediata al salir del método donde fue declarada, ya que el tipo que es manejado en el stack.

Usando una estructura
Para el siguiente ejemplo he considerado usar una estructura para definir un tipo que podría usar como un tipo numérico con campos y métodos estáticos, los cuales pueden ser invocados sin tener que crear una instancia; además declaro métodos públicos que se pueden invocar una vez que se creo un tipo de la estructura; Estos métodos se pueden usar para realizar algunos cálculos. La estructura tienen el nombre InteresMensual, enseguida el código.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UsandoStructuras
{
    class Program
    {

        struct InteresMensual
        {
            public static float Minimo = 1f;
            public static float Maximo = 100f;


            // campos privados
            private float _cantidad;
            private float _interes;


            /// <summary>
            /// constructor con 1 parámetro
            /// </summary>
            /// <param name="interes"></param>
            public InteresMensual(float interes)
            {
                this._interes = interes;
                this._cantidad = 0;
            }

         
            /// <summary>
            /// constructor con 2 parámetros
            /// </summary>
            /// <param name="interes"></param>
            /// <param name="cantidad"></param>
            public InteresMensual(float interes, float cantidad)
            {
                this._interes = interes;
                this._cantidad = cantidad;
            }

            /// <summary>
            /// Propiedad
            /// </summary>
            public float Cantidad
            {
                get { return _cantidad; }
                set { _cantidad = value; }
            }

            /// <summary>
            /// Propiedad
            /// </summary>
            public float Interes
            {
                get { return _interes; }
                set { _interes = value; }
            }

            /// <summary>
            /// Método estatico, que puede llamarse sin crear una instacia
            /// de la estructura, no es posible usar los valores de las variables
            /// que son manejados como propiedades, tampoco se puede usar la
            /// palabra clave this para tener acceso a ellos porque el método es
            /// estatico.
            /// </summary>
            /// <param name="cantidad"></param>
            /// <returns></returns>
            public static float CalculaInteresMinimo(float cantidad)
            {
                return (Minimo / 100) * cantidad;
            }

            /// <summary>
            /// Método estatico, que puede llamarse sin crear una instacia
            /// de la estructura, no es posible usar los valores de las variables
            /// que son manejados como propiedades, tampoco se puede usar la
            /// palabra clave this para tener acceso a ellos porque el método es
            /// estatico.
            /// </summary>
            /// <param name="cantidad"></param>
            /// <returns></returns>
            public static float CalculaInteresMaximo(float cantidad)
            {
                return (Maximo / 100) * cantidad;
            }


            /// <summary>
            ///
            /// </summary>
            /// <returns></returns>
            public float CalculaInteres()
            {
                return ( this._interes / 100) * this._cantidad;
            }

            /// <summary>
            ///
            /// </summary>
            /// <param name="interes"></param>
            /// <returns></returns>
            public float CalculaInteres(float interes)
            {
                this._interes = interes;
                return (this._interes / 100) * this._cantidad;
            }

            /// <summary>
            ///
            /// </summary>
            /// <param name="interes"></param>
            /// <param name="cantidad"></param>
            /// <returns></returns>
            public float CalculaInteres(float interes, float cantidad)
            {
                this._interes = interes;
                this._cantidad = cantidad;

                return (this._interes / 100) * this._cantidad;
            }


        }



        static void Main(string[] args)
        {
            InteresMensual interesMensual = new InteresMensual(20);

            Console.WriteLine("Interes mínimo mensual: {0}", InteresMensual.Minimo);
            Console.WriteLine("Interes máximo mensual: {0}", InteresMensual.Maximo);
            Console.WriteLine();
            Console.WriteLine("Interes mínimo calculado : {0}", InteresMensual.CalculaInteresMinimo(100));
            Console.WriteLine("Interes máximo calculado : {0}", InteresMensual.CalculaInteresMaximo(100));
         
            Console.WriteLine();


            InteresMensual otroInteres = new InteresMensual();

            // acceso a propiedades, también es posible llamar a los
            // constructores con parámetros.
            otroInteres.Interes = 20f;
            otroInteres.Cantidad = 100f;

            Console.WriteLine("De la cantidad: {0} con interes de : {1} se paga mensual: {2} ",
                otroInteres.Cantidad, otroInteres.Interes,
                otroInteres.CalculaInteres());


            Console.WriteLine("De la cantidad: {0} con interes de : {1} se paga mensual: {2} ",
            otroInteres.Cantidad, 15f,
            otroInteres.CalculaInteres(15));
            Console.WriteLine("De la cantidad: {0} con interes de : {1} se paga mensual: {2} ",
            otroInteres.Cantidad, otroInteres.Interes = 20,
            otroInteres.CalculaInteres(20, 200));

        }
    }
}


Los siguientes puntos deben tenerse en mente al trabajar con estructuras

  • Los constructores son opcionales, pero si se incluyen, estos deben usar parámetros. No podemos ni debemos crear un  constructor por omisión -es decir sin parámetros - de eso se encarga el compilador.
  • No se puede definir un valor por omisión para un campo en la declaración del mismo.
  • A los campos se les puede dar valores solamente usando el constructor o bine después de que la estructura ya fue declarada.
  • Los miembros privados pueden ser inicializados usando solamente el constructor.
  • En necesario usar la palabra new para crear un tipo de una estructura. 
  • Si la estructura tienen un elemento de tipo referencia debe llamar al constructor del tipo de forma explicita.


Referencias libros:
Microsoft Visual C# Step by Step, editorial 
MCSD Certification ToolKit (Exam 70-483)



martes, 12 de enero de 2016

Uso de tipos por valor y sus alias en C#

Enseguida el código con comentarios para explicar el tema.

using System;

namespace UsoDeTiposPorValorYAlias
{
    class Program
    {
        static void Main(string[] args)
        {
            // Primero creamos una una variable, usando la forma de alias
            // es decir usando la palabra clave "int"
            // para almacenar un tipo por valor, sin asignarle uno.
            //
            // En la segunda declaración definimos una variable usando
            // "new", aquí hay una asignación de valor por omisión. A diferencia
            // de la declaración anterior
            int unIntSinAsignar;
            int otroIntUsaNew = new int();

            // Creamos una variable para almacenar un tipo por valor .NET
            // este tipo es la version .NET del uso de alias "int"
            // observe el uso de la palabra clave "new", estamos creando
            // un objeto desde la clase System.Int32
            System.Int32 ahoraUnInt32 = new System.Int32();

            // Esta instuccion debera ser comentada porque Visual Studio
            // nos muestra un error al intentar usar una variable sin asignar
            // Esto previene de intentos de uso inadecuado donde
            // solo se ha apartado memoria y no se ha asignado valor.
            Console.WriteLine(unIntSinAsignar);

            // Ahora imprimimos el valor por omisión asignado a una variable
            // que no tiene un valor asignado previamente, pero en la
            // que se uso la palabra clave "new" en la declaración.
            Console.WriteLine(otroIntUsaNew);

            // Esta declaración trabaja bien e imprime
            // el valor por omisión (default)para el tipo por valor
            Console.WriteLine(ahoraUnInt32);

        }
    }
}

Un aspecto básico que debe conocerse es el que C# maneja los tipos por valor en localidades de memoria que se conoce como el stack .

También existe otra esquema de administración de memoria que es utilizado para los tipos por referencia, que es utilizado por el motor del CLR y que se le llama heap.





domingo, 10 de enero de 2016

Regular Expressions in C# 1 (Introducción a Expresiones Regulares en C# 1)

Empezare presentando algunos conceptos, luego analizaré uno ellos y finalmente mediante una aplicación en C# aplicare las expresiones regulares desde lo más simple a algo más complejo.

Nota
Es importante ejecutar o construir el código para ir avanzado de lo más simple a lo complejo y notar como el motor de C# hace uso de las expresiones regulares. He usado el libro, "Introducing Regular Expressions", Editorial O'REILLY, Michael Fitzgerald, y otras fuentes.

He encontrado algunas definiciones para el concepto de expresiones regulares, por ejemplo la Wikipedia y he encontrado algo como lo que sigue:

Una expresión regular, a menudo llamada también regex, es una secuencia de caracteres que forma un patrón de búsqueda, principalmente utilizada para la búsqueda de patrones de cadenas de caracteres u operaciones de sustituciones.

Otro ejemplo tomado del libro, "Introducing Regular Expressions", Editorial O'REILLY, Michael Fitzgerald.

Las expresiones regulares son cadenas de texto especialmente codificadas usadas como patrones para encontrar las coincidencias dentro de otra cadena de texto.

Las expresiones regulares son cadenas de texto..., es decir son letras, números  y símbolos que usamos de forma cotidiana en nuestra escritura...
especialmente codificadas... cuando decimos que son "codificadas", significa que usamos un "código" y un código tiene las siguientes acepciones, según la RAE (Real Academia Española) -he colocado en negritas la acepción que considero adecuada a nuestro tema tratado-.

Del lat. codex, -ĭcis 'código' y -ficar.1. tr. Hacer o formar un cuerpo de leyes metódico y sistemático.2. tr. Transformar mediante las reglas de un código la formulación de un mensaje.3. tr. Registrar algo siguiendo un código (‖ combinación de letrasnúmeros u otroscaracteres).

 Es decir que usamos las letras, números y símbolos de acuerdo a reglas (leyes) de forma metódica y sistemática y transformamos mediante estas reglas el mensaje que deseamos armar, construir, o escribir, y lo hacemos para comunicarnos en el mundo de las expresiones regulares.  

Así que cuando escribimos estas expresiones seguimos un código, y decimos entonces que están codificadas, y podemos decir que son especiales porque las reglas para su escrituras no son del uso cotidiano o común.

usadas como patrones... la palabra "patrón" creo que debe ser clarificada y nuevamente me auxiliare del diccionario de la RAE (he colocado en negritas la acepción que considero adecuada a nuestro tema tratado). 


patrón

Del lat. patrōnus; la forma f., del lat. patrōna.En acep. 7, u. t. el m. para referirse a una mujer.1. m. y f. Defensorprotector.2. m. y f. Santo titular de una iglesia.3. m. y f. Santo elegido como protector de un pueblo o congregación religiosaprofesional ocivil.4. m. y f. Dueño de la casa donde alguien se aloja u hospeda.5. m. y f. señor (‖ persona a la que sirve un criado).6. m. y f. patrono (‖ persona que emplea trabajadores).7. m. y f. Persona que manda un pequeño buque mercante o una embarcación de recreo.8. m. Modelo que sirve de muestra para sacar otra cosa igual.9. m. Metal que se toma como tipo para la evaluación de la moneda en un sistema monetario.10. m. Planta en que se hace un injerto.11. f. Galera inmediatamente inferior en dignidad a la capitana de una escuadra.

Entonces un patrón es un modelo, entonces, cada vez que escribimos un cadena de texto que sigue las reglas de escritura del  mundo de las expresiones regulares buscamos sacar otra cosa igual y lo hacemos colocando nuestro modelo frente a otras cadenas de texto mediante una aplicación.

Así que ahora sabemos que el objetivo que siguen las expresiones regulares es encontrar coincidencias dentro de otras cadenas de texto.

Las expresiones regulares datan de la década de 1940 pero se usan en el mundo de la programación en la década de 1970. Tienen un uso intenso en editores de texto de UNIX como; ed, sed, vi y otros. Además de ser un tema del examen de certificación, 70-483 Programming in C# de Microsoft.

Usare una aplicación de C# haciendo uso del motor de expresiones regulares de .NET, Regex MSDN Microsoft, este motor es definido como sigue:
El Regex clase representa el motor de expresiones regulares de .NET Framework.Se puede utilizar para analizar rápidamente grandes cantidades de texto para buscar modelos de caracteres específicos; para extraer, modificar, reemplazar o eliminar subcadenas de texto; y para agregar las cadenas extraídas a una colección para generar un informe.
En la aplicación de ejemplo avanzaremos en el uso de expresiones regulares desde lo más simple hacia lo complejo, tomando en cuenta que es una introducción. El ejemplo no tiene control de ciclo y se ejecuta con CTRL+F5.

Ejemplo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ExprecionesRegularesIntro
{
    class Program
    {
        static void Main(string[] args)
        {

            // Buscaremos las coincidencias o Match
            // en la cadena de los digitos del 0 al 9
            // y se expresa asi: [0-9]
            // se le llama: character class o character set
            //ContieneAlaExpresion("abcd123efg", @"[0-9]");

            // Puede limitarse el rango, especificando
            // que digitos deseamos.
            //ContieneAlaExpresion("abcd123efg", @"[12]");

            // Buscaremos las coincidencias en un número
            // con la siguiente estructura 044-55-1234-5678
            //ContieneAlaExpresion("055-44-5678-1234",
            //    @"[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]");

            // Buscaremos las coincidencias en un número
            // con la siguiente estructura 044-55-1234-5678
            // pero la ahora hemos colocado letras en la cadena
            // para hacer notar que no se encontraron Match
            //ContieneAlaExpresion("04a-5b-a234-z678",
            //    @"[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]");

            // Una forma más rápida y simple es usar
            // \b  - este character shorthand (simbolo taquigrafico o caracter taquigrafico)
            // busca las coincidencias de cualquier digito de: 0 a 9
            //ContieneAlaExpresion("abcd123efg", @"\d");

            // Ahora usaremos: \b
            // Buscaremos las coincidencias en un número
            // con la siguiente estructura 044-55-1234-5678
            //ContieneAlaExpresion("044-54-1234-8678",
            //    @"\d\d\d-\d\d-\d\d\d\d-\d\d\d\d");

            // Ahora usaremos: \b
            // Buscaremos las coincidencias en un número
            // con la siguiente estructura 044-55-1234-5678
            //ContieneAlaExpresion("a44-54-b234-8678",
            //    @"\d\d\d-\d\d-\d\d\d\d-\d\d\d\d");

            // Ahora usaremos: \b ... asi mismo: \D
            // Hemos usado el guión: "-" de forma directa
            // pero podemos usar: \D que define cualquier caracter que
            // no sea un numero.
            // Pruebe colocando una letra en vez de cualquier numero
            // para ver el efecto del Match
            //ContieneAlaExpresion("044-54-1234-8678",
            //    @"\d\d\d\D\d\d\D\d\d\d\d\D\d\d\d\d");

            // Ahora usaremos: \b ... podemos usar el caracter punto: "."
            // el caracter punto es un comodin y puede representar
            // cualquier caracter (excepto en ciertas situaciones, al fin de linea)
            // Pruebe colocando una letra en vez de cualquier numero
            // para ver el efecto del Match
            //ContieneAlaExpresion("044-54-1234-8678",
            //    @"\d\d\d.\d\d.\d\d\d\d.\d\d\d\d");
            //ContieneAlaExpresion("044|54|1234|8678",
            //    @"d\d\d.\d\d.\d\d\d\d.\d\d\d\d");
            //ContieneAlaExpresion("044%54%1234%8678",
            //    @"\d\d\d.\d\d.\d\d\d\d.\d\d\d\d");


            // USANDO CUANTIFICADORES (se ha utilizado nuevamente el guión: "-")
            // los numeros entre llaves: {} definen cuantos digitos
            // deberan aparecer en la cadena evaluada.
            //
            // El uso de cuantificadores hace más concisa la expresión.
            //
            // el simbolo: ? es otro cuantificador y al aparecer despues del guion ("-")
            // significa que este es opcional, es decir, puede o no estar presente.
            // Pruebe retirando el guion de la cadena para ver el efecto.
            //ContieneAlaExpresion("044-54-1234-8678",
            //    @"\d{3}-?\d{2}-?\d{4}-\d{4}");


            // Pruebe el uso de la expresion con diferentes opciones en la cadena
            // conla que se hace el Match
            //
            // Explicación del uso de la expresion siguiente y sus cauntificadores.
            // ( ... inicia una agrupación
            // \ ... define el inicio del uso de un caracter taquigrafico (character shorthand)
            // d ... define el caracter taquigrafico y marca el fin del uso del mismo.
            // { ... inicia el cuantificador de cantidad de caracteres.
            // 2 ... minima cantidad de caracteres que coincidan.
            // , ... el separador de cantidad.
            // 4 ... máxima cantidad de caracteres que coincidan.
            // } ... cierre del cuantiquicador
            // [ ... define el inicio de una agrupación de caracteres que se toman
            //       de forma literal, sin aplicar las reglas de las expresiones regulares
            //       y se conoce como: clase de caracteres
            // .  ... define que se usara el caracter punto (" . ")
            // -  ... define el uso del guión (" - " )
            // ]  ... cierre de la: clase de caracteres
            // ?  ... cero o un cuantificador, puede o no aparecer, en este caso un guión o
            //        un punto
            // )  ... cierre de grupo
            // +  ... uno o mas cuantiicadores
            // Pruebe retirando el guion de la cadena para ver el efecto.
            // se han colocado mas numeros y la coicidencia es localizada
            //ContieneAlaExpresion("044.54.1234-8678-4512-9999-45",
            //    @"(\d{2,4}[.-]?)+");

            // en el ejemplo anterior se observo que la coincidencia se produce
            // pero si deseamos tener una evaluación estricta de un numero con
            // vamos a mejorar un poco la expresión.
            // Observe que la cadena puede ser mas larga y el motor
            // mandara coincidencia.
            //ContieneAlaExpresion("044-54-1234-8678",
            //    @"\d{3}[.-]?\d{2}[.-]?(\d{4}[.-]?){2}");

            // Ahora vamos a definir que los primeros tres caracteres de la cadena
            // sean opcionales de aparecer: 044
            // el resultado es que hay coincidencia, en los dos primeros y el tercero no.
            //ContieneAlaExpresion("55-1234-8678",
            //    @"(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}");
            //ContieneAlaExpresion("044-55-1234-8678",
            //    @"(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}");
            //ContieneAlaExpresion("1234-8678",
            //    @"(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // no hay coincidencia



            // Ahora
            // 1er. ESTRICTO inicio de la cadena
            // y ademas con tres numeros,  en este caso: 044
            // tambien limitamos que aparezcan numeros o guiones al inicio de
            // la cadena.
            //ContieneAlaExpresion("55-1234-8678",
            //    @"^(\d{3}[.-])\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // NO hay coincidencia

            // 2. ESTRICTO inicio donde los primeros tres caracteres de la cadena
            // deben aparecer.
            //ContieneAlaExpresion("044-55-1234-8678",
            //    @"^(\d{3}[.-])\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // hay coincidencia

            // 3. Se marca INICIO, donde los primeros tres caracteres de la cadena
            // puden o no parecer, pero se define que es inicio de cadena
            //ContieneAlaExpresion("044-55-1234-8678",
            //    @"^(\d{3}[.-])\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // hay coincidencia
            //ContieneAlaExpresion("55-1234-8678",
            //    @"^(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // hay coincidencia

             //4. INICIO donde los primeros tres caracteres de la cadena
             //puden o no parecer, pero no otros caracteres.
            //ContieneAlaExpresion("22-044-55-1234-8678",
            //    @"^(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // NO hay coincidencia
            //ContieneAlaExpresion("044-55-1234-8678",
            //    @"^(\d{3}[.-])\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // hay coincidencia
            //ContieneAlaExpresion("55-1234-8678",
            //    @"^(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}"); // hay coincidencia


            // 5. Ahora definiremos el fin de la cadena
            // para hacer Match ... el caracer utilizado es: $
            //ContieneAlaExpresion("044-55-1234-8678",
            //    @"^(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}$"); // HAY coincidencia
            //ContieneAlaExpresion("044-55-1234-8678-",
            //    @"^(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}$"); // NO hay coincidencia
            //ContieneAlaExpresion("044-55-1234-8678-22",
            //    @"^(\d{3}[.-])?\d{2}[.-]?(\d{4}[.-]?)\d{4}$"); // NO hay coincidencia


            // finalmente hemos conseguido que la cadena coincida con un
            // la estructura de los numeros celulares de la ciudad de México
            // de forma estricta.
            // Existen mejoras para la expresión pero eso se vera
            // en un nuevo tema, más avanzado.

        }

        static void ContieneAlaExpresion(string inputData, string regExPattern)
        {

            Console.WriteLine("Buscando coindidencias en ..." + inputData);
            Console.WriteLine();

            Regex rgx = new Regex(regExPattern, RegexOptions.ExplicitCapture);
            MatchCollection matches = rgx.Matches(inputData);
            if (matches.Count > 0)
            {
                Console.WriteLine("HAY coincidencias en: {0} ... se encontraron: {1} y son:", inputData, matches.Count);
                Console.WriteLine();
                foreach (Match match in matches)
                    Console.WriteLine("  " + match.Value);
             
             
            }
            else { Console.WriteLine("NO HAY elementos coincidentes.");  }
            Console.WriteLine();

        }

    }
}