NLog1 C#: Configuración versión de la aplicación con App.Config

Voy a continuar con  NLog: Sistema de logging gratuito y de código abierto para .Net.

Proyecto en GitHub NLog1.

He añadido algunas mejoras sin relación con el propio NLog,  Algo esencial para el control del proyecto es la gestión de versiones para controlar los cambios realizados (yo sigo este esquema de versionado siempre Semantic Versioning 2.0.0). El fichero App.config del proyecto en VS2012 con sintaxis XML es el candidato ideal para alojar la información de la versión del proyecto añadiendo a mano un nuevo bloque “<appSettings>” y dentro una etiqueta con clave valor :

Otra forma de definir la versión si queremos tratarla posteriormente en nuestra aplicación es definir 3 parámetros clave valor para X.Y.Z de la versión (MAJOR.MINOR.PATCH).

Poder acceder a la información de la versión desde el código de nuestra aplicación es esencial, sobre todo si queremos condicionar la ejecución de un bloque de código especial dependiendo de la versión por ejemplo. Para ello debemos añadir la referencia “System.Configuration” al proyecto y el espacio de nombres a nuestra aplicación:

using System.Configuration;

Para acceder a la variable desde nuestro programa es muy sencillo:

Como conclusión, podemos añadir la información que necesitemos, algunos usos muy comunes es incluir información de conexión a la base de datos o configuración del usuario.

Referencias externas:

 

 

 

Anuncios

C# ThreadingBasics (II): Operaciones básicas con Threads

Código en GitHub

GetThreadState: Determinar el estado de un thread

El siguiente ejercicio nos permite obtener información valiosa sobre el estado de un Thread. Añadimos los siguientes métodos:t1

Y añadimos el siguiente código a la función principal Main:

t1

El Thread pasa por varios estados, podemos obtener el estado del hilo accediendo a la propiedad ThreadState que es un campo enumerado.

Inicialmente el estado del Thread t1 es Unstarted antes de ser arrancado. Cuando invocamos el método Start() inmediatamente pasa al estado Running. La llamada a Sleep provoca que pase al estado WaitSleepJoin. Finalmente la llamada Abort hace que pase a estado Aborted. El thread t2 finaliza con normalidad y su estado estado final es Stopped.

TheadPriority: Establecer prioridad en la ejecución de un thread


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

using System.Threading;

namespace TheadPriority
{
class ThreadSample
{
private bool _isStopped = false;

public void Stop()
{
this._isStopped = true;
}

public void CountNumbers()
{
long counter = 0;
while (!this._isStopped)
{
counter++;
}
Console.WriteLine("{0} with {1,11} priority " +
"has a count = {2,13}",
Thread.CurrentThread.Name,
Thread.CurrentThread.Priority,
counter.ToString("N0"));
}
}

class Program
{
static void RunThreads()
{
var sample = new ThreadSample();
var t1 = new Thread(sample.CountNumbers);
t1.Name = "t1";
var t2 = new Thread(sample.CountNumbers);
t2.Name = "t2";

t1.Priority = ThreadPriority.Highest;
t2.Priority = ThreadPriority.Lowest;

t1.Start();
t2.Start();

Thread.Sleep(TimeSpan.FromSeconds(10));
sample.Stop();
}

static void Main(string[] args)
{
Console.WriteLine("Main: current thread priority: {0}",
Thread.CurrentThread.Priority);
Console.WriteLine("Main: Calling RunThreads()");
RunThreads();
Console.WriteLine("Press any key to exit....");
Console.ReadLine();
}
}
}

C# ThreadingBasics: Operaciones básicas con threads

Creando un thread en C#

Vamos a crear una aplicación de consola. Añadimos el espacio de nombres using System.Threading;. Creamos una función static PrintNumbers (los hilos no retornan nada ni reciben parámetros) que escribe por consola del 1 al 10 usando un bucle for.

t1

Una instancia de un programa en ejecución se puede definir como un proceso. Un proceso consiste en uno o más threads. Esto significa que cuando ejecutamos un programa, siempre tenemos un thread principal que ejecuta el código del programa.

El método PrintNumbers lo invocaremos dos veces, desde el Main y como thread o hilo concurrente.

t2

Pausando un thread

En el siguiente ejemplo dentro de la función PrintNumbersWithDelay hacemos una llamada al método Thread.Sleep que  suspende la ejecución durante 2 segundos (usamos la estructura TimeSpan para con el método  FromSeconds para convertir de segundos en milisegundos, la magnitud reconocida por el método Sleep).

t1

Haciendo que un thread espere

En este caso vamos a hacer que la función principal Main detenga su ejecución  y espere a que el el thread acabe. Usamos el método Thread.Join()  que bloquea el subproceso de llamada hasta que finaliza el subproceso representado por esta instancia, si le pasásemos un valor al método esperaría el tiempo especificado a que el thread finalice.

t1Abortando la ejecución de un thread

Ahora el hilo principal Main espera 6 segundos y aborta la ejecución del thread con el método Abort() que lanza la excepción ThreadAbortException en el subproceso en el que se invoca.

t1 No es muy recomendable usar el método Abort ya que el resultado puede ser incierto.

 

C# MsgPrinterThead: Subprocesamiento múltiple

Introducción

Poder realizar varias operaciones en paralelo de o de forma concurrente es esencial en cualquier lenguaje de programación cuando construimos aplicaciones avanzadas. La biblioteca de clases de .NET framework cuenta con primitivas para el subprocesamiento mútiple. El espacio de nombres (namespace) que debemos incluir es System.Threading.

Los subprocesos transitan por varios estados durante su ciclo de vida. Dos clases básicas para el subprocesamiento del namespace System.Threading son Thread y Monitor.

thread

Un objeto Thread inicialmente está inactivo (Unstarted) cuando el programa crea el objeto (un objeto es una instancia de una clase) y pasa un delegado ThreadStart al constructor del objeto.

thread1

El delegado ThreadStart permite especificar la acción que realizará el proceso durante su ciclo de vida debe declararse como un método que no retorne (void) y sin parámetros:

thread2

El subproceso se mantiene en estado Unstarted hasta que llamamos al método Start de la clase Thread que arranca el hilo multitarea (Running). thread3

En ese momento ejecuta el método especificado por su delegado ThreadStart. Podemos forzar la parada del subproceso en cualquier momento llamando al método Abort. El método Abort lanza una excepción ThreadAbortException en el subproceso.

Primer programa con tareas concurrentes

La aplicación crea 3 hilos que imprimen un mensaje por consola antes y después de pasar por un Sleep de un número de milisegundos aleatorio para cada método.

Creamos un nuevo proyecto de consola y le damos nombre “MsgPrinterThead” por ejemplo, inicialmente antes de comenzar:

 thread4

Lo primero es incluir el espacio de nombres System.Threading.

Clase clsMsgPrinterThead

Vamos a crear una nueva clase dentro del espacio de nombres y la llamaremos “clsMsgPrinterThead”, la clase contiene dos miembros privados para contener el número aleatorio que generemos en el constructor de la clase y que será el valor empleado para pausar la ejecución del método Print llamado como subproceso.

thread5

 Ahora en el constructor generaremos un valor aleatorio entre 0 y 5000 y lo guardamos en iSleepTime.

thread6

Definimos un método que será el que se llame para cada hilo multitarea:

thread7

Ahora que ya hemos definido la clase y su método que será ejecutado de forma concurrente vamos a ver las llamadas para crear los 3 subprocesos desde el Main.

Creación de Thread-s

thread8

Código completo:

</p>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Threading;

namespace MsgPrinterThead
{
/**
* Clase clsMsgPrinterThead
* El constructor genera un número de forma aleatoria que será usado como tiempo de inactividad del
* hilo cuando pausemos su ejecución con el método...
*/
class clsMsgPrinterThead
{
private int iSleepTime; //< Timepo inactividad cuando se pause ejecución.
private static Random myRandom = new Random(); //< Clase para genear números aleatorios.

public clsMsgPrinterThead()
{
//Tiempo de inactividad aleatorio entre 0 y 5s (5000 milisegundos)
iSleepTime = myRandom.Next(5001);
}

public void Print()
{
Thread actual = Thread.CurrentThread;
Console.WriteLine("{0} va a estar inactivo {1} miligsegundos",
actual.Name,this.iSleepTime);
Thread.Sleep(this.iSleepTime);
Console.WriteLine("{0} dejo de estar inactivo.",actual.Name);
}
}

class Program
{
static void Main(string[] args)
{
clsMsgPrinterThead Printer1 = new clsMsgPrinterThead();
Thread subproceso1 = new Thread(new ThreadStart(Printer1.Print));
subproceso1.Name = "subproceso1";

clsMsgPrinterThead Printer2 = new clsMsgPrinterThead();
Thread subproceso2 = new Thread(new ThreadStart(Printer2.Print));
subproceso2.Name = "subproceso2";

clsMsgPrinterThead Printer3 = new clsMsgPrinterThead();
Thread subproceso3 = new Thread(new ThreadStart(Printer3.Print));
subproceso3.Name = "subproceso3";

subproceso1.Start();
subproceso1.Abort();

subproceso2.Start();
subproceso3.Start();
}
}
}
<p style="text-align: justify;">

C# Clases PruebaTiempo1: Clase básica

El siguiente ejemplo consta de una clase Tiempo1, contiene 3 variables privadas (private) de instancia de tipo entero (int):  hora, minuto y segundo. Representan la hora en formato de tiempo universal (formato reloj de 24 horas donde los valores de cada miembro se encuentran en un rango de 0 a 23).  La clase Tiempo1 contiene los métodos public accesibles desde otras clases:  EstablecerTiempoAStringUniversalToString. El constructor no se declara por lo que el compilador emplea uno predeterminado. Cada variable de instancia recibe de forma implícita el valor 0 por defecto para un int (podemos hacer la prueba modificando el acceso a las variables con public e imprimiendo su valor por consola sin inicializar), aunque también podemos inicializarlas de la misma forma que una variable local.

tiempo1_1

El método  EstablecerTiempo es public y recibe tres parámetros de entrada que permiten establecer la hora. Dentro del método se evalúan si los datos de entrada son válidos, si el valor de entrada no está dentro del rango 0 a 23 para la hora se asigna un 0 por defecto (lo mismo para minutos y segundos si no están comprendidos entre 0 y 60). Para ello se emplea un operador condicional ternario (ver referencia operador ? en MSDN). De esta forma nos aseguramos que a pesar de que introduzcamos datos no válidos el valor es consistente.

tiempo1_3

El método  AStringUniversal no recibe argumentos y retorna un objeto de tipo string en formato de hora universal con forma “HH:MM:SS”.  utilizamos el método static Format del objeto string para darle la forma deseada, “{0:D2}:{1:D2}:{2:D2}”  con 2 dígitos y donde sea necesario un cero a la izquierda.

tiempo1_4Con “D2” indicamos por ejemplo que se trata de un decimal entero (“D”), el 2 lo usamos como especificador de precisión, rellenará la cadena final con ceros por la izquierda hasta que el número alcance 2 dígitos de longitud (ver MSDN Cadenas con formato numérico estándar).

El método  ToString no recibe argumentos y retorna un objeto String en formato AM/PM. Cabe destacar la palabra clave  override o sobrecarga, todos los objetos en C# tienen un método ToString que devuelve una representación en forma de cadena (también otros como GetType o Equals). Usando el modificador override ampliamos su implementación original.

tiempo1_5

Por ejemplo: Cuando declaramos un objeto de tipo String el método ToString se llama de forma implícita cuando usamos Console.Write con el objeto.

tiempo1_6

Uso de la clase Tiempo1

Después de declararla podemos usarla de las siguientes formas:

tiempo1_7

 


/*
* Created by SharpDevelop.
* User: i.landajuela
* Date: 20/12/2016
* Time: 10:54
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;

namespace PruebaTiempo1
{
//Clase tiempo para mantener la hora
class Tiempo1
{
//3 variables privadas de instancia private de tipo int
//Se inicializan a 0 por defecto
private int hora; //0 - 23
private int minuto; //0 - 59
private int segundo; //0-59

//Establece un nuevo valor de tiempo usando la hora universal, controla
//lo datos invalidos haciendolos consistentes
public void EstablecerTiempo(int h, int m, int s)
{
this.hora = ( (h>=0 && h<24) ? h : 0 );
this.minuto = ( (m>=0 && m<60) ? m : 0 );
this.segundo = ( (s>=0 && s<60) ? s : 0 );
}

//Convierte en string en formato universal HH:MM:SS
public string AStringUniversal()
{
return string.Format("{0:D2}:{1:D2}:{2:D2}",
this.hora,this.minuto,this.segundo);
}

//Convierte en string, en formato hora estándar H:MM:SS AM o PM)
//Sobrecargamos la función ToString
//
public override string ToString()
{
return string.Format("{0}:{1:D2}:{2:D2}:{3}",
((hora==0||hora==12)? 12 : (hora % 12)),
this.minuto,
this.segundo,
( hora < 12 ? "AM" : "PM"));
}
}


class Program
{
public static void Main(string[] args)
{
Tiempo1 objT1;

objT1.EstablecerTiempo(23,30,01);

Console.WriteLine("Como hora universal: {0}.",objT1.AStringUniversal());
Console.WriteLine("Usando método .ToString sobrecargado: {0}.",objT1.ToString());

Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}

&nbsp;

C# ConsoleArrayBasics: Declaración de arrays y operaciones básicas


using System;

namespace ConsoleArrayBasics
{
class Program
{
public static void Main(string[] args)
{
//-------------------------------------------------
//Declaramos un array de enteros
int[] array1 = new int[8];
array1[0]=1;
array1[1]=2;
//... si no asignamos valor rellena a ceros
for (int i=0;i<=array1.Length-1;i++)
{
Console.WriteLine("array1{0}]={1}",i,array1[i]);
}
Console.WriteLine();

//-------------------------------------------------
//Declaramos e inicializamos con valores un array
int[] array2 = {1,2,3,4};
for (int i=0;i<=array2.Length-1;i++)
{
Console.WriteLine("array2[{0}]={1}",i,array2[i]);
}

//-------------------------------------------------
//Array de strings
string[] semana={"Lunes","Martes","Miércoles","Jueves","Viernes","Sábado","Domingo"};
foreach(string dia in semana)
{
Console.WriteLine(dia);
}

//-------------------------------------------------
//Cambiar dimensión de un array

//-------------------------------------------------
//Comprobar si existe una determinada cadena en un array de strings.
string stringToCheck = "GHI";
string[] stringArray = { "ABC", "DEF", "GHI", "JKL" };
foreach (string x in stringArray)
{
if (x.Equals (stringToCheck))
{
Console.WriteLine("Find the string ..." + x);
}
}

//-------------------------------------------------
//clone array
string[] array = { "dot", "net", "perls" };
//El metodo clone de un array retorna un tipo de objeto genérico clonado
//debemos aplicarle un casting string[] para convertirlo.
string[] cloned = array.Clone() as string[];

//Join es un metodo de la clase string pasandole como primer parámetro
//la cadena como separador de elementos y el segundo parámetro es un array
//de strings, concatena todos los elementos en una cadena
Console.WriteLine(string.Join(",", array)); //Salida: "dot,net,perls"
Console.WriteLine(string.Join(",", cloned));
Console.WriteLine();

// Change the first element in the cloned array.
cloned[0] = "element";

Console.WriteLine(string.Join(",", array));
Console.WriteLine(string.Join(",", cloned));


//-------------------------------------------------
//copy array
int[] source = new int[5];
source[0] = 1; source[1] = 2; source[2] = 3; source[3] = 4; source[4] = 5;
int[] target = new int[5];

Array.Copy(source, target, 5); //el 3º parámetro es la longitud

Console.WriteLine("--- Target array ---");
foreach (int value in target)
{
Console.WriteLine(value);
}


//-------------------------------------------------
//Arrays con diferentes tipos de datos


Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}