sábado, 9 de julio de 2022

Curso avanzado de C#. Creación e implementación de jerarquías de clases

Heredar de una clase base La sección "Creación de tipos de referencia", explica cómo crear clases. El siguiente código muestra la definición de una clase Persona simple y debe ser familiar para  nosotros

Public Class Persona

{

       Public String Nombre { Get; Set; }

       Public String Apellido { Get; Set; }

       Public Persona(String nombre, String apellido)

       {

             // Valida el nombre y el apellido

             If (( nombre == null) || (nombre .Length < 1))

                    Throw New ArgumentOutOfRangeException(

                    "Nombre", nombre,

                    "El nombre no puede ser nulo o quedar en blanco.");

             If ((apellido == null) || (apellido .Length < 1))

                    Throw New ArgumentOutOfRangeException(

                    "Apellido", apellido,

                    "El  apellido no puede ser nulo o quedar en blanco.");

                    // Guarda el nombre y el apellido.

                    Nombre = nombre;

                    Apellido = apellido;

       }

}

La clase Persona contiene dos propiedades de cadena implementadas automáticamente: Nombre y Apellido. (Una clase utilizada por una aplicación real probablemente tendría muchas más propiedades para contener información como como la dirección postal, números de teléfono y direcciones de correo electrónico). Nuestro constructor toma los nombres y apellidos como parámetros, realiza alguna validación y guarda los valores en las propiedades Nombre y Apellido.

Curso avanzado de C#. Creación e implementación de jerarquías de clases
Fotos similares a esta aquí


Ahora supongamos que queremos  crear una clase de Empleado que tenga las propiedades Nombre, Apellido y NombreDepartamento. Podemos construir esta clase desde cero, pero necesitaremos las mismas propiedades que las de la clase Persona y necesitaremos las mismas validaciones, por lo que crearlo desde cero requeriría duplicar  todo ese código. Una mejor solución es derivar la clase Empleado de la clase Persona para que herede de la clase padre los campos, propiedades, métodos y eventos. Un empleado es una especie de persona, por lo que tiene sentido que la clase Empleado derive desde la clase Persona. No hay ninguna razón por la que el mismo código dentro de la clase Persona no funcionara también para los objetos  de la clase Empleado. 

Terminología de clases

Hay mucha terminología en torno a las jerarquías de clases. Cuando derivamos una clase de otra, la nueva clase hereda todo el código incluido en la clase original. En este caso, la clase original se llama padre clase, clase base o superclase. La nueva clase se llama clase derivada, hija, secundaria, o subclase. Derivar una clase de otra se llama subclasificación. 

_________________________________________________


Para derivar una clase de otra, simplemente hay que poner el nombre de la clase con dos puntos y luego el nombre de la clase principal. El siguiente código muestra una clase  empleado que se deriva de la clase persona. 

Public Class Empleado :  Persona

{

    Public String NombreDepartamento { Get; Set; }

}

En este ejemplo, la clase Empleado hereda los campos, propiedades, métodos y eventos definidos por la clase Persona. También agrega una nueva propiedad, Nombre Departamento. Aunque una clase secundaria hereda la mayoría del código en su clase padre, no hereda el constructor de la clase. En este punto, un programa podría utilizar el siguiente código para crear un objeto Empleado sin inicializar sus propiedades Nombre y Apellido:

Empleado empleado = new Empleado();

Dado que este código no inicializa las propiedades Nombre y Apellido del empleado, estas tienen los valores nulos, lo que anula el propósito del constructor de la clase Persona. La solución es hacer que los constructores de la clase secundaria llamen a los constructores de la clase principal. 

Llamar a constructores de clases principales 

Para asegurarse de que se llama al constructor de la clase Persona para validar el Nombre y Apellido del empleado. Debemos darle un constructor a la clase Empleado, con  una lista de argumentos del constructor seguida por dos puntos, la clase base y cualquier parámetro que deseemos pasar al constructor de la clase base.

En este ejemplo, el constructor Empleado debe pasar el nombre y apellido que recibe al Constructor de la clase de persona. El código resaltado muestra dónde el constructor llama al constructor de la clase base : 

Public Class Empleado :  Persona

{

      Public String NombreDepartamento { Get; Set; }

      Public Empleado(String Nombre, string Apellido,

      string nombredepartamento)

            :base(Nombre, Apellido)

      {

            // Valida NombreDepartamento.

            If ((nombredepartamento == null) || (nombredepartamento.Length < 1))

            Throw New ArgumentOutOfRangeException(

            "nombredepartmento", nombredepartmento,

            "NombreDepartamento no debe ser nulo o estar en vacío.");

            // Graba el Nombre del Departamento.

            NombreDepartmento = nombreDepartmento;

      }

}

Si la clase base tiene varios constructores, la clase secundaria puede usar la palabra clave base para invocar cualquiera de ellos. El programa usa los argumentos que siguen a la palabra clave base para averiguar qué constructor utilizar. 

Nota: Cuando un constructor utiliza la palabra clave base para invocar un constructor de la clase base, El constructor de la clase base se ejecuta antes que el cuerpo del hijo. 

Si tanto la clase principal como la secundaria tienen constructores, el constructor de la clase secundaria debe invocar uno de los constructores de la clase padre. Esto significa que la llamada al constructor en la clase base que hemos resaltado arriba, requiere un fragmento de código. Si eliminamos ese código, Visual Studio muestra el mensaje de error "JerarquiaPersona no contiene un constructor que tome 0 argumentos". (Aquí, JerarquiaPersona es el espacio de nombres que contiene la clase Persona.) El constructor de la clase Empleado está tratando implícitamente de acceder a un constructor de Persona que no toma parámetros y no puede encontrar uno. Una rareza de este sistema es que podemos crear una clase Empleado sin constructores aunque  permite al programa crear una instancia de la clase Empleado sin invocar un constructor de la clase Persona. Eso significa que la siguiente definición para la clase Empleado es legal: 

Public Class Empleado :  Persona

{

      Public String NombreDepartamento { Get; Set; }

}

Si deseamos evitar que el programa eluda los constructores de la clase principal, debemos dotar la clase secundaria de al menos un constructor.

Llamar a constructores de la misma clase 

A menudo, es conveniente dar a una clase varios constructores para realizar diferentes tipos de inicialización. Dependiendo de qué parámetros se pasen al constructor. En ese caso, varios constructores puede que necesiten realizar las mismas tareas. Por ejemplo, supongamos que la clase Persona tiene las propiedades Nombre y Apellido y queremos permitir que el programa cree un objeto Persona especificando solo el nombre o nombre y apellido. 

Class Persona

{

     Public String Nombre { Get; Set; }

     Public String Apellido { Get; Set; }

     // Constructor con nombre.

     Public Persona(String nombre)

     {

          Nombre = nombre;

     }

     // Constructor con Nombre y Apellido.

     Public Persona(String nombre, String apellido)

     {

          Nombre =  nombre;

          Apellido = apellido;

     }

}

El primer constructor toma un nombre como parámetro y lo almacena en la propiedad Nombre. El segundo constructor toma el nombre y el apellido como parámetros y guarda sus valores en las Propiedades Nombre y Apellido. En este código, el segundo constructor comienza realizando el mismo trabajo que el primer constructor hace cuando guarda el nombre. En un escenario mas complicado en el que los constructores realizan tareas más difíciles, esta repetición de código sería un problema. Significaría varias copias del mismo código para implementar, depurar y mantener. Una forma de evitar esta duplicación de código es hacer que un constructor llame a otro. En este podríamos reescribir el segundo constructor para que llame al primer constructor para que pueda manejar el parámetro de nombre. Para ello, hacemos que el constructor invoque a un segundo constructor de la misma manera que se invoca a un constructor de la  clase base, excepto que utiliza la palabra clave this en lugar de la palabra clave base. 

El siguiente código muestra cómo el segundo constructor de la clase Persona puede invocar a su primer constructor. Se resalta el código que invoca al primer constructor. 

// Constructor con Nombre y Apellido.

Public Persona(String nombre, String apellido)

      :this(nombre)

{

      Apellido = apellido;

}

Nota: Cuando un constructor utiliza la palabra clave this para invocar un segundo constructor en la misma clase, el segundo constructor se ejecuta antes de que se ejecute el cuerpo del primer constructor. 

Si derivamos la clase Empleado de la clase Persona y la clase Empleado incluye una propiedad NombreDepartamento. Es posible que queramos diferentes constructores de empleados que puedan tomar como parámetros nombre, nombre y apellido, o nombre y apellido y nombre de departamento. Estos constructores pueden utilizar la misma técnica que se muestra en esta versión de la clase Persona para hacer que los constructores más complicados invoquen a los más simples. Los constructores Empleado también pueden utilizar la palabra clave base descrita en la sección anterior para invocar a los constructores de la clase Persona. Por ejemplo, el constructor Empleado(nombre, apellido,nombredepartamento) podemos utilizar esta técnica para invocar al constructor Empleado( nombre, apellido) y ese constructor puede utilizar la palabra clave  base para invocar al constructor de Persona(nombre, apellido). 







sábado, 2 de julio de 2022

Curso de Photoshop: Balance de blancos

Utilizaremos el balance de blancos para eliminar los tonos amarillentos o azulados de nuestras fotos en interiores.

Para ello, vamos a Brigde y abrimos la foto con camera raw. 

Abrir en cámara raw adobe photoshop brigde


En la parte derecha arriba tenemos Equilibrio de blancos y 
una lista desplegable de la que podemos elegir el tipo de balance de blancos que deseemos.

Balance de blancos Photoshop


Así por ejemplo si hicimos la foto bajo luz fluorescente podemos elegir la opción de fluorescente o la de flash si 
hicimos la foto con flash.

Una vez elegido el balance de blancos predeterminado, podemos ajustarlo aun más desplazando las barras de temperatura y matiz si consideramos que la foto aun es demasiado cálida o fría. Teniendo en cuenta que no deberemos de desplazar estas barras exageradamente hacia la izquierda o la derecha.

Temperatura y matiz en balance de blancos


La barra de temperatura añadirá a la imagen colores más cálidos (amarillos) o más fríos (azules) y la de matiz se desplazará entre los colores rosados y los verdes.

Un método más exacto para ajustar el balance de blancos consiste en pulsar sobre la herramienta Equilibrio de blancos de la barra superior y después pinchar con ella sobre un área blanquecina o grisácea de nuestra foto, esto ajustará automáticamente nuestra foto.

Herramienta de Equilibrio de blancos Photoshop


Balance de blancos


Si no nos gusta el resultado, podemos pulsar sobre un área diferente hasta que el resultado sea el deseado.

Al fin y al cabo el balance de blancos es una decisión creativa de cada uno, de modo que si el anterior método aunque es el más exacto, no nos convence, podemos variarlo. Si el resultado de esta herramienta no nos convence, haciendo doble click sobre el icono de la herramienta de equilibrio de blancos, podemos volver al resultado inicial.

Si una vez elegida la herramienta de equilibrio de blancos hacemos click con el botón derecho del ratón sobre la foto, también se mostrará un menú como el del principio  botón.

Balance de blancos Brigde photoshop


sábado, 25 de junio de 2022

Curso avanzado de C#. Formateo de cadenas

 Formatear valores

Dar formato a un valor para su visualización es una conversión de tipo particularmente importante. Hasta que no se convierta una variable Datetime, decimal o double en algún tipo de cadena, no podremos mostrarla al usuario. Dos de los métodos más útiles para formatear valores como cadenas son ToString y String. Métodos que se describen a continuación.  

ToString 

El objeto de la clase proporciona un método ToString que heredan todas las demás clases. De forma predeterminada, este método devuelve el nombre del tipo de un objeto como una cadena, pero la mayoría de las clases para las que tiene sentido anulan este método para devolver el valor del objeto como una cadena. 

Por ejemplo, si una variable float tiene el valor 1,23, el método ToString devuelve el valor "1,23" como cadena. Por el contrario, si definimos una clase empleado, de forma predeterminada el método ToString devuelve el nombre de la clase, que es similar a WindowsFormsApplication1.Employee. Si utilizamos el método ToString de una variable sin parámetros, obtenemos una representación predeterminada de su valor. El método ToString también podemos tomar como parámetros un proveedor de formato, una cadena de formato o ambos. Al utilizar la cadena de formato, podemos personalizar el texto resultante. Por ejemplo, si la variable costo es un valor flotante (float), la declaración cost.ToString ("0.00") produce una cadena que contiene el valor del costo que se muestra con 2 posiciones decimales. 

Curso avanzado de C#. Formateo de cadenas


String.Format

El método ToString nos permite convertir el valor de una sola variable en una cadena. El método de formato estático de la clase String nos permite crear una cadena que puede contener los valores de muchas variables formateadas de diferentes maneras. El método String.Format tiene algunas versiones sobrecargadas, pero la más común toma como parámetros una cadena de formato y uno o más argumentos que se utilizan para completar elementos dentro de la cadena de formato. Cada elemento en la cadena de formato tiene la siguiente sintaxis de formato compuesto: 

{index [,length] [:formatString]} 

Aquí, índex es el índice de base cero de un parámetro que sigue a la cadena de formato que debe usarse para este elemento; length es la longitud mínima del resultado del elemento; y formatString es una cadena de formato estándar o personalizada para el elemento. Si la longitud es negativa, el valor se alinea a la izquierda dentro de su longitud.

Esto formalmente lo hace parecer confuso, pero en realidad no es tan mala. El siguiente código muestra un ejemplo sencillo. 

int i = 163; 

Console.WriteLine(string.Format("{0} = {1,4} or 0x{2:X}", (char)i, i, i)); 

Utilizamos string.Format para formatear una línea que escribe en la ventana de Salida.

La cadena de formato es {0} = {1,4} or 0x{2:X}. Esta cadena tiene tres elementos de formato que significan: 

{0} muestra el argumento 0 como formato predeterminado 

{1,4} muestra el argumento 1 en un campo de al menos cuatro caracteres de ancho 

{2: X} muestra el argumento 2 con formato cadena X (que muestra un número entero en hexadecimal)

Los otros caracteres dentro de la cadena de formato (=, y or x) se incluyen en la salida tal como aparecen en la cadena de formato. 

Los parámetros que vienen después de la cadena de formato son los argumentos que deben usarse con la cadena de formato. El primer argumento convierte el entero i en un carácter. El segundo y tercer argumento son simplemente la variable i. El resultado es que esta línea muestra el valor 163 convertido en un carácter, luego como un valor decimal y luego en hexadecimal. A continuación se muestra el resultado: 

£ = 163 or 0xA3 

No es necesario utilizar un argumento en la cadena de formato. Los argumentos también se pueden usar en cualquier orden y se pueden usar repetidamente, por lo que la siguiente declaración es válida: 

string text = string.Format("{1} {4} {2} {1} {3}", 

"quién", "yo", "luego", "soy", "pienso"); 

Si utilizamos String.Format para concatenar una serie de declaraciones y producir resultados es en gran parte una cuestión de preferencia personal. 

Formateo de cadenas 

Tanto los métodos ToString como String.Format pueden tomar cadenas de formato como parámetros para indicarles cómo formatear un valor. Para String.Format, esto se refiere a la cadena de formato dentro de los elementos de formato. Por ejemplo, en la declaración string.Format("0x{0:X}", 90) , la cadena de formato es la X dentro de las llaves. Las cadenas de formato se dividen en dos categorías generales: 


Las cadenas de formato estándar permiten determinar  cómo queremos que se muestre un valor en un nivel alto.

Las cadenas de formato estándar tienen en cuenta la configuración regional, por lo que permiten que el programa produzca una salida que sea apropiada para la configuración regional del ordenador. Por ejemplo, la  cadena de formato de fecha "d" indica un patrón de  fecha corto y produce un resultado similar al 4/7/2022 en los Estados Unidos o al 7/04/2022 en España. 

Las cadenas de formato personalizadas nos permiten  crear formatos que no son proporcionados por las  cadenas de formato estándar. Por ejemplo, la siguiente declaración produce un resultado similar a:  Son las 12  en punto.

Console.WriteLine(string.Format("Son     las {0:HH} en punto",DateTime.Now)); 

Podemos usar cadenas de formato personalizadas para producir resultados que sean similares a los producidos por las cadenas estándar, pero debemos utilizar las cadenas estándar siempre que sea posible para obtener los cambios apropiados si nuestro programa se ejecuta en un ordenador que este configurada para una configuración local diferente. 

Los métodos ToString y String.Format comprenden cientos de cadenas de formato estándar y personalizadas. La tabla siguiente enumera las cadenas de formato estándar más útiles para valores numéricos y Datetime

Cadenas de formatos para números estándard

 

Formato

Descripción

Ejemplo

C o c

Moneda

12.345,67  €

D o d

Decimal, sólo tipos enteros

12345

E o e

Notación científica

1.234567E+004

F o f

Punto fujo

12345,67

G o g

General (punto fijo o científico, lo que sea más corto)

12345,67

N o n

Número con decimales y separadores de miles

12.345,67

P o p

Porcentaje (multiplicado por 100 y añadido %)

0,12 se convierte en 12 %

X o x

Hexadecimal (sólo tipos integer)

3039

 

Algunos de estos formatos pueden tener un especificador de precisión opcional que controla el número de dígitos desplegado. Para la mayoría de estos tipos, el especificador de precisión indica el número de dígitos que se mostrarán después de la coma. Por ejemplo, si el valor es 12345,67, value.ToString ("C4") produce 12.345,6700 €.

Para la notación científica, el especificador de precisión indica el número de dígitos después de la coma en la mantisa. Por ejemplo, si el valor es 12345,67, value.ToString ("E2") produce 1,23E + 004.

Cadenas de formato para Datetime

 

Formato

Descripción

Ejemplo

d

Fecha corta

7/04/2022

D

Fecha larga

Jueves 7 de abril de 2022

f

Completa con hora corta

Jueves 7 de abril de 2022 14:23

F

Completa con hora larga

Jueves 7 de abril de 2022 14:23:16

g

General con hora corta

7/04/2022 14:23

G

General con hora larga

7/04/2022 14:23:16

m o M

Dia/ mes

7 /Abril

t

Hora corta

14:23

T

Hora larga

14:23:16

y o Y

Mes / año

Abril 2022

Además de estos formatos estándar, la estructura DateTime proporciona cuatro métodos que producen una salida similar a los especificadores de formato d, D, t y T. Estos métodos son ToShortDateString, ToLongDateString, ToShortTimeString y ToLongTimeString. 

Ejemplo Visualización de valores de moneda 

Modificamos el formulario de entrada de pedidos que creamos para el Manejo Valores porcentuales para que muestre el precio extendido, el subtotal, el impuesto sobre las ventas y el total general en formato de moneda.

Solución: El programa ya usa el método ToString para mostrar esos valores. El único cambio necesario es pasar la cadena de formato de moneda "C" a esas llamadas a ToString. Por ejemplo, el siguiente código muestra cómo el programa muestra el Gran Total en formato de moneda:

txtTotal.Text = Total.ToString("C"); 


sábado, 18 de junio de 2022

Como desactivar el firewall de Windows

Hay ocasiones en las que aunque no es recomendable, tenemos que desactivar el firewall de Windows. 

Para desactivar el firewall de Windows basta con pulsar sobre el panel de control en el icono principal de Windows, o teclearlo en la caja de texto si no lo vemos. Una vez en el panel de control elegimos Sistema y seguridad.

Como desactivar el firewall de Windows

Esto nos abrirá una pantalla desde la que pulsamos sobre Firewall de Windows Defender.

Como desactivar el firewall de Windows


En la siguiente pantalla vemos si están activadas las diferentes opciones de seguridad de nuestro equipo, a la izquierda vemos una lista de opciones, pulsamos sobre Cambiar la configuración de notificaciones.

Como desactivar el firewall de Windows

Nos abrirá una pantalla similar a la anterior en la que podemos activar o desactivar las diferentes opciones del Firewall para la red de Dominio, red privada o red pública.

Como desactivar el firewall de Windows



sábado, 11 de junio de 2022

Curso Avanzado de C#. Manipulación de cadenas II

Clases String adicionales 

La clase String es intuitiva y fácil de usar. Podemos utilizar sus métodos para examinar fácilmente las cadenas, eliminar secciones, recortar el inicio o el final de una cadena y extraer subcadenas. Sin embargo, la forma inusual en que se introducen cadenas en nuestro programa, las hace ineficaces para algunos propósitos. La figura muestra el programa de ejemplo de permutaciones.

Clases String adicionales


Este programa muestra una cadena grande que contiene todas las permutaciones de un conjunto de letras entre la A y la H. Hay 8 letras y (5040 permutaciones de esas ocho letras) por lo que el resultado es 5040 cadenas concatenadas. Para empeorar las cosas, el programa crea cada permutación con un carácter cada vez, por lo que cada permutación requiere la construcción de ocho cadenas más pequeñas. Esto significa que el programa construye 8 × 5040 = 40.320 cadenas en total, cada una de las cuales debe ser ingresada. Como resultado, el programa es bastante lento, tardando aproximadamente 23 segundos en producir estas 5.040 permutaciones utilizando la concatenación de cadenas. Para casos especiales como este, cuando la clase String es particularmente ineficiente, un programa puede obtener un mejor rendimiento utilizando las clases de procesamiento de cadenas especializadas: 


StringBuilder 

StringWriter 

StringReader 

El programa tomó solo 0.05 segundos para construir las permutaciones cuando utilizamos StringBuilder en lugar de concatenaciones de String. Cada una de estas clases de procesamiento de cadenas se describe en las siguientes secciones. 

StringBuilder 

La clase StringBuilder representa una cadena mutable no internada. Almacena datos de caracteres en una matriz y puede agregar, eliminar, reemplazar y agregar caracteres sin crear un nuevo objeto String o usar el grupo interno. Normalmente, un programa usa un StringBuilder para construir una cadena en una larga serie de pasos y luego llama al método ToString de StringBuilder para convertir el resultado en una cadena normal. Por ejemplo, el siguiente código utiliza StringBuilder para construir una cadena que contiene una serie de nombres de empleados en líneas separadas:

String[] NombresEmpleados =

{

      "Abel",

      "Bartolo",

      "Carlos",

      "David",

};

StringBuilder allNames = New StringBuilder();

foreach (string name in NombresEmpleados)

{

      allNames.Append("[" + name + "]" + Environment.NewLine);

}

txtEmpleados.Text = allNames.ToString();

El código comienza definiendo una matriz de nombres de empleados. Luego crea un StringBuilder y recorre los nombres en la matriz NombresEmpleados. Para cada nombre, el código llama al método Append de StringBuilder para agregar el nombre entre corchetes a la cadena. Una vez que ha procesado todos los nombres, el código llama al método ToString de StringBuilder para convertirlo en un String normal y muestra el resultado en la caja de texto txtEmpleados

La Tabla describe las propiedades más útiles de la clase StringBuilder.

 

Propiedad

Descripción

Capacity

Obtiene o establece el número de caracteres que puede contener StringBuilder. Si la cantidad de texto almacenado en StringBuilder excede esta cantidad, el objeto asigna más espacio. Si sabe que StringBuilder debe contener al menos un cierto número de caracteres, podemos utilizar esta propiedad para hacer que el objeto se preasigne

memoria en lugar de asignar memoria de forma incremental. Algunas versiones sobrecargadas del constructor de la clase  permiten especificar una capacidad inicial.

Length

Obtiene o establece el número actual de caracteres almacenados en StringBuilder. Si establecemos este valor a un menor valor que la longitud actual, el texto en StringBuilder se trunca.

El indexador de StringBuilder devuelve los caracteres almacenados en el objeto. Un programa puede usar el indexador para obtener y establecer valores de caracteres. Por ejemplo, la declaración allNames [10] = 'X' establece el carácter número 10 en X. 

La tabla describe los métodos más útiles de la clase StringBuilder.

 

Método

Descripción

Append

Añade una representación de cadena de un objeto al final del texto de StringBuilder

AppendFormat

Formatea una serie de objetos y agrega el resultado al final del texto de StringBuilder

EnsureCapacity

Garantiza que StringBuilder tenga al menos una capacidad determinada

Insert

Inserta una representación de cadena de un objeto en una posición dada en el texto de StringBuilder

Remove

Elimina un rango de caracteres del texto de StringBuilder

Replace

Reemplaza todas las instancias de un carácter o cadena con un nuevo carácter o cadena

ToString

Devuelve una representación de cadena normal del texto de StringBuilder

 

La clase StringBuilder agrega algo de sobrecarga a un programa y, a veces, hace que el código sea más difícil de leer, por lo que generalmente debemos usarlo solo si realizamos una gran cantidad de operaciones de cadena. En un conjunto de pruebas, la concatenación de cadenas simple fue más rápida que la creación y el uso de StringBuilder para menos de aproximadamente siete concatenaciones.

También hay que tener en cuenta en cuenta que los tiempos involucrados para algunas operaciones de cadena son pequeños. Pero utilizar StringBuilder para concatenar 10 cadenas puede ser un poco más rápido que realizar 10 concatenaciones simples de cadena, pero la cantidad total de tiempo ahorrado se mide en milisegundos. A menos que el programa repita esa operación muchas veces o haga concatenaciones mucho más largas, podemos sacrificar algunos milisegundos para que el código sea más fácil de entender. 

StringWriter 

La clase StringWriter proporciona una interfaz que facilita en algunos casos la creación de una cadena en un StringBuilder subyacente. La clase StringWriter proporciona métodos que facilitan la escritura secuencial de valores en una cadena. La tabla  describe los métodos más útiles de StringWriter. 

 

Método

Descripción

Flush

Vacía los datos almacenados en búfer en el StringWriter subyacente

ToString

Devuelve el contenido actual del objeto como una cadena

Write

Añade un elemento a los datos de la cadena. Las versiones sobrecargadas agregan char, string, int, double y otros muchos tipos de datos.

WriteAsync

Anexa de forma asíncrona un char,string o una matriz de caracteres al final de los datos de la cadena

WriteLine

Agrega un elemento a los datos de la cadena como lo hace Write y luego agrega una nueva línea

 

StringWriter puede ser útil cuando solo deseamos agregar valores a una cadena. StringWriter también implementa una interfaz TextWriter, lo que puede ser útil cuando otras clases requieren un TextWriter para producir una salida y deseamos almacenar esa salida en una cadena. Por ejemplo, el método Serialize de la clase XmlSerializer envía la salida a un TextWriter. Si queremos serializar en una cadena, podemos enviar la salida a StringWriter y luego usar el método ToString de StringWriter para obtener el resultado. Si necesita manipular los datos de la cadena subyacente de otras formas, como eliminar o reemplazar caracteres, StringBuilder proporciona más flexibilidad. 

StringReader 

La clase StringReader proporciona una implementación TextReader que lee fragmentos de datos tomados de un StringBuilder subyacente. Proporciona métodos que facilitan la lectura secuencial de fragmentos de texto de una cadena. La tabla  describe los métodos más útiles de StringReader.

 

Método

Descripción

Peek

Devuelve el siguiente carácter en los datos pero no avanza al carácter

Read

Devuelve el siguiente carácter de los datos y avanza al siguiente carácter. Una versión sobrecargada puede leer un bloque de caracteres

ReadAsync

Lee de forma asíncrona caracteres de StringReader en un búfer

ReadBlock

Lee hasta un número máximo de caracteres de StringReader en un búfer que comienza en un índice especificado

ReadBlockAsync

Lee asincrónicamente hasta un número máximo de carácteres de StringReader en un búfer que comienza en un índice especificado.

ReadLine

Lee carácteres de StringReader hasta que encuentra el final de línea

ReadLineAsync

Lee de forma asíncrona los caracteres de StringReader hasta que encuentra el fin de la línea

ReadToEnd

Devuelve el texto restante de StringReader como una cadena

ReadToEndAsync

Devuelve de forma asíncrona el texto restante de StringReader como una cadena

 

La clase StringReader proporciona acceso a los datos de StringBuilder a un nivel relativamente bajo. A menudo, un programa usa un StringReader solo porque necesita pasar información a un método predefinido que requiere un StringReader o TextReader como parámetro. 

Veamos un ejemplo: Usando StringBuilder 

Usando solo StringBuilders (sin Strings), escribir un programa que muestre todas las subsecuencias iniciales de las letras del alfabeto A, AB, ABC, y así sucesivamente en un TextBox, como se muestra en la figura 

StringBuilder

Private void Form1_Load(Object sender, EventArgs e)

{

      // Genera un StringBuilder sosteniendo los ABC

      StringBuilder letters =

      New StringBuilder("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

      // Éste contiene la siguiente línea de letras.

      StringBuilder line = New StringBuilder();

      // Crea el resultado StringBuilder.

      StringBuilder result = New StringBuilder();

      // Recorre las letras.

      For (int i = 0; i < 26; i++)

      {

            // Agregua la siguiente letra a la línea.

            line.Append(letters[i]);

            //Agrega una línea al resultado.

            result.AppendLine(line.ToString());

      }

      // Muestra el resultado.

      stringBuilderTextBox.Text = result.ToString();

      stringBuilderTextBox.Select(0, 0);

}

El código construye un StringBuilder que contiene las letras del alfabeto. Hace un segundo StringBuilder para mantener una línea de salida y un tercero para mantener el resultado final. A continuación, el código recorre los números del 0 al 25. Para cada valor de i, el código agrega el i-ésimo carácter en letras al valor en línea. Luego agrega el nuevo valor de línea al resultado, siguiéndolo con una nueva línea. Cuando el código termina su ciclo, muestra el resultado. En este ejemplo, no está claro si usar StringBuilder es más rápido que usar concatenaciones de cadenas simples. En una prueba que ejecutó este código y un código similar que realizó concatenaciones de cadenas 100.000 veces, la versión de StringBuilder tomó aproximadamente el 54 por ciento de tiempo, por lo que hay un ahorro de tiempo, pero el resultado para una sola ejecución es insignificante.