0% encontró este documento útil (0 votos)
89 vistas30 páginas

Programacion en C Sharp

El documento resume las diferentes versiones del lenguaje de programación C#. La primera versión se parecía a Java y carecía de características como genéricos e iteradores. La versión 2 introdujo genéricos, iteradores y otros avances. La versión 3 consolidó a C# como un lenguaje formidable al introducir LINQ, expresiones lambda y otros. Versiones posteriores continuaron mejorando el lenguaje con características como programación asíncrona y tipos dinámicos.

Cargado por

Kevyn Porras
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
89 vistas30 páginas

Programacion en C Sharp

El documento resume las diferentes versiones del lenguaje de programación C#. La primera versión se parecía a Java y carecía de características como genéricos e iteradores. La versión 2 introdujo genéricos, iteradores y otros avances. La versión 3 consolidó a C# como un lenguaje formidable al introducir LINQ, expresiones lambda y otros. Versiones posteriores continuaron mejorando el lenguaje con características como programación asíncrona y tipos dinámicos.

Cargado por

Kevyn Porras
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 30

Portada

Introducción
Historia
Durante el desarrollo de la plataforma .NET, las bibliotecas de clases fueron
escritas originalmente usando un sistema de código gestionado llamado Simple
Managed C (SMC). En abril de 1999, Anders Hejlsberg formó un equipo con la
misión de desarrollar un nuevo lenguaje orientado a objetos. Este nombre tuvo
que ser cambiado debido a problemas de marca, pasando a llamarse C#.1 La
biblioteca de clases de la plataforma .NET fue migrada entonces al nuevo
lenguaje, este después fue modificado por Joseth M.
Hejlsberg lideró el proyecto de desarrollo de C#. Anteriormente, ya había
participado en el desarrollo de otros lenguajes como Turbo Pascal, Delphi y J++.
El nombre C Sharp fue inspirado por el signo '#' que se compone de cuatro signos
'+' pegados. En inglés, "C Sharp" también significa "Do Sostenido", que en música
indica que una nota debe ser un semitono más aguda. Esto hace referencia al
lenguaje C++, donde el símbolo "++" indica que se debe incrementar la variable en
1 tras ser evaluada.
C# Versión 1
Cuando echas la vista atrás, la primera versión de C# sí que se parecía un montón
a Java. Como parte de sus objetivos de diseño escritos para ECMA, buscaba ser
un "lenguaje orientado a objetos de uso general moderno y sencillo". En aquel
momento, podría haber hecho algo peor que mirar hacia Java para alcanzar
dichos fines.

Pero si analizases la versión 1.0 de C# 1.0 hoy, te marearías. Carecía de


capacidades asíncronas sólidas y de muchas de las "pulidas" funcionalidades
relacionadas con los genéricos que hoy en día damos por sentadas. En realidad,
carecía de genéricos en general. ¿Y LINQ? Nada. Eso tardaría aún unos cuantos
años en salir.

La versión 1 de C# parecía estar bastante desprovista de funcionalidad,


comparado con hoy. Al final te veías escribiendo código pesado. Pero bueno,
como con cualquier versión 1.0: por algún lado hay que empezar...

C# Versión 2
Aquí las cosas se empiezan a poner interesantes. Repasemos algunas de las
principales características de C# 2.0, lanzado en 2005, junto con Visual Studio
2005 (no te olvides de echarle un vistazo al libro escrito por el creador de
NDepend, Patrick Smacchia, sobre .NET 2.0, disponible en inglés y francés).
Genéricos
Tipos parciales
Métodos anónimos
Tipos anulables
Iteradores
Covarianza y contravarianza
Aunque Microsoft puede que haya empezado con un lenguaje orientado a objetos
bastante genérico, la versión 2 de C# lo cambió todo enseguida. Se pusieron a la
tarea tras la salida de la versión inicial y fueron a por varias de las frustraciones
que causaba. Y lo hicieron muy en serio.

Con genéricos, tienes tipos y métodos que pueden operar sobre un tipo arbitrario
mientras que aún conservan seguridad de tipos. Así, por ejemplo, tener una
List<T> te permite tener una List<string> o una List<int> y realizar operaciones
seguras de tipo en esas cadenas de caracteres o ints mientras iteras por ellas.
Esto es mucho mejor que crear clases derivadas de listas (ListInt?) o convertir a
un Objeto para cada operación.

¡Ah!, y hablando de iteradores, la versión 2 de C# los presentó. Para resumir, esto


te permite iterar por los ítems de una Lista (u otros tipos Enumerable) con un bucle
foreach. Tener esto como un elemento de primera clase del lenguaje mejoró
ostensiblemente la legibilidad del código y la capacidad para poder entenderlo.

Y aún así, Microsoft seguía intentando ponerse a la altura de Java. Java ya había
liberado versiones que incluían genéricos e iteradores. Pero eso cambiaría pronto
a medida que los lenguajes seguían una evolución diferente.

C# Versión 3
La versión 3 de C# apareció a finales de 2007, junto con Visual Studio 2008,
aunque la funcionalidad completa aparecería con la versión 3.5 de C#. ¡Y menuda
actualización resultó ser!. Yo me atrevería a afirmar que ese momento consolidó a
C# como un lenguaje de programación realmente formidable. Veamos algunas de
sus características principales en esta versión:
Propiedades auto-implementadas
Tipos anónimos
Expresiones de consulta - LINQ
Expresiones lambda
Árboles de expresión
Métodos de extensión
Con mirada retrospectiva, muchas de estas características parecen tanto
inevitables como inseparables. De hecho, no es fácil destacar una sobre otra ya
que todas encajan estratégicamente muy bien juntas.

Otros haciendo este mismo análisis no tendrán ese problema, y dirán que, de
largo, la novedad más importante de la versión 3 de C# fue las expresiones de
consulta, también conocidas como LINQ (Language INtegrated Query).

Yo creo que hay más matices y sutilezas puesto que, desde mi punto de vista, los
árboles de expresión, las expresiones lambda y los tipos anónimos fueron los
cimientos sobre los que se creó LINQ. Disertaciones aparte, lo cierto es que nos
encontramos con un concepto realmente revolucionario. Microsoft había
empezado a allanar el terreno para hacer de C# un lenguaje funcional orientado a
objetos híbrido.

En concreto, con esta versión ya se podían programar búsquedas declarativas tipo


SQL para llevar a cabo operaciones en colecciones, entre otras cosas. En vez de
tener que crear un bucle para computar la media de una lista de enteros, ahora se
podía hacer con algo tan fácil como list.Average(). La combinación de expresiones
de búsqueda y métodos de extensión hizo parecer que las listas de enteros se
habían hecho más inteligentes.

Llevó un tiempo hasta que los programadores realmente entendieron cómo


integrar el concepto, pero a la larga lo lograron. Y ahora, unos años más tarde, el
código es mucho más conciso, sencillo y funcional.

C# Versión 4
La versión 4 de C# nació con el estigma de no suponer una innovación rompedora
como sí lo había sido su antecesora versión 3. Y es que con la versión 3, Microsoft
hizo que el lenguaje dejase de estar a la sombra de Java y empezó a destacar.
Rápidamente el lenguaje se estaba convirtiendo en una opción elegante.

De todos modos, la versión 4 de C# sí introdujo alguna cosas chulas.

Tipos dinámicos
Argumentos opcionales y con nombre
Covarianza y contravarianza genérica
Tipos interop embebidos
Los tipos interop embebidos aliviaron problemas a la hora del despliegue. La
covarianza y contravarianza genéricas te dan mucha potencia, pero son
demasiado académicas y probablemente sean más valoradas entre los creadores
de frameworks y bibliotecas. Los argumentos opcionales y con nombre te permiten
eliminar muchas sobrecargas de método y ofrecen comodidad. Pero ninguna de
estas cosas altera el paradigma propiamente dicho.

Esa distinción sí se la llevan los tipo dinámico. Con esta característica, Microsoft
introdujo en la versión 4 de C# la capacidad de anular el compilador al tiparlo en
tiempo de compilación. Es decir, al usar el tipo de referencia dinámico, te puedes
llegar a pegar un tiro en el pie como en los lenguajes de tipado dinámico como
JavaScript. Puedes crear una "x = cadena de caracteres" dinámica y luego
añadirle 6, dejando al tiempo de ejecución determinar qué diablos tiene que pasar
después.

Esto lo digo un poco de broma obviamente. Está claro que cabe la posibilidad de
cometer errores, pero también otorga mucha potencia dentro del lenguaje.

C# Versión 5
Con la versión 5 de C#, Microsoft liberó una versión con el foco muy puesto en la
innovación del lenguaje. Esta es la lista de las características más importantes:

Programación asincrónica con Async y Await


Atributos Caller info
No quiero que se me malinterprete. El atributo caller info está muy bien. Te
permite recuperar información sobre el contexto en el que estás sin tener que
recurrir a un montón de código reflejo repetitivo. Me encanta esta funcionalidad en
realidad.

Pero async y await son las verdaderas estrellas de esta versión. Cuando esto salió
en 2012, Microsoft cambió las reglas del juego nuevamente al meter la asincronía
en el lenguaje como un participante de primera clase. Si ya has gestionado
operaciones largas y la implementación de páginas web con retro-llamadas,
probablemente adores esta funcionalidad.

C# Versión 6
Con las versiones 3 y 5, Microsoft había hecho algunas cosas bastante
impresionantes en un lenguaje orientado a objetos (la versión 2 también, pero
estaban copiando conceptos de Java con esas funciones que introdujeron). Con la
versión 6 se alejaron de la idea de sacar una novedad dominante estrella y, en vez
de eso, liberaron muchas características para hacer felices a los usuarios del
lenguaje de programación. Aquí enumero unas cuantas:

Importaciones estáticas (como en Java)


Filtros de excepciones
Inicializadores de propiedad
Miembros con una expresión como cuerpo
Propagador null
Cadenas interpoladas
Operador nameof
Inicializador del diccionario
Si las vemos de forma individual, todas estas características del lenguaje son muy
interesantes. Pero si las valoramos en conjunto, observamos un patrón que nos
llama la atención. En esta versión, Microsoft se ha esforzado en eliminar
repeticiones en el lenguaje y hacer que el código sea más ligero y legible. Así que
para los aficionados del código escueto y limpio, esta versión del lenguaje fue una
gran victoria.
¡Ah!, e hicieron otra cosa con esta versión, aunque no se puede considerar como
una función tradicional del lenguaje, per se. Liberaron Roslyn, el compilador, como
servicio. Microsoft ahora usa C# para hacer C#, y te dejan usar el compilador
como parte de tus esfuerzos de programación.

C# Versión 7
Finalmente hemos llegado ya a la versión 7 de C#. Es la versión actual en la fecha
que se ha escrito este artículo. Tiene cosas muy chulas y revolucionarias que ya
estaban en el ADN de la versión 6, pero sin el compilador como servicio. Aquí van
las novedades de esta versión:

Variables out
Tuplas y deconstrucción
Coincidencia de patrones
Funciones locales
Extensión de la funcionalidad de miembros con una expresión como cuerpo
aparecida en C# 6
Referencias locales y devoluciones
Todas ofrecen nuevas capacidades para que los desarrolladores puedan escribir
código más limpio que nunca. En concreto, creo que Microsoft ha dado solución a
problemas que venían desde muy lejos al condensar la declaración de variables
que se pueden a usar con la palabra clave out y al permitir valores de devolución
múltiples vía tuplas.

Además, Microsoft le está dando un uso más amplio al lenguaje. .NET ahora va
dirigido a cualquier sistema operativo y tiene la vista puesta de forma firme en la
nube y en la portabilidad. Esto es lo que más ocupa la mente y el tiempo de los
diseñadores del lenguaje, además de pensar en nuevas características.

Conozco C# desde hace 15 años, y el lenguaje ha estado bajo desarrollo más


tiempo que eso. Será emocionante ver qué funcionalidades y características
deparará el futuro.
C# y Net
Originalmente, C# funcionaba únicamente como una extensión de programación
orientada a objetos creada por Microsoft como parte de su plataforma .NET, que
después fue aprobado como un estándar por la ECMA (ECMA-334) e ISO
(ISO/IEC 23270).
Su sintaxis básica deriva de C/C++ y utiliza el modelo de objetos de la
plataforma .NET, similar al de Java, aunque incluye mejoras derivadas de otros
lenguajes.
Aunque C# forma parte de la plataforma .NET, ésta es una API, mientras que C#
es un lenguaje de programación independiente diseñado para generar programas
sobre dicha plataforma. Ya existe un compilador implementado que provee el
marco Mono - DotGNU, el cual genera programas para distintas plataformas como
Windows Microsoft, Unix, Android, iOS, Windows Phone, Mac OS y GNU/Linux.
Lo que liga a ambas es su conexión que originalmente compartieron y que todavía
comparten, por los orígenes de dichos programas. Sin embargo, hace tiempo ya
que C# tomo su propio camino gracias a las actualizaciones posteriores y a su
capacidad de funcionamiento individual. No obstante, dicha dependencia inicial le
generaría problemas a futuros (Como el ser incapaz de definir instrucciones de
entrada y salida)

Librerías

Las librerías en C# permiten hacer nuestros programas más modulares y


reutilizables facilitando además crear programas con funcionalidades bastante
complejas en unas pocas líneas de código. Son especialmente recomendadas en
este lenguaje debido a que complementan enormemente las informaciones y
facilitan la elaboración de las líneas de código.
Algunos recomendados
Collections/Generics: Algunas de las clases que proporciona son Deque,
MultiDictionary, Bag, OrderedBag, OrderedDictionary, Set, OrderedSet u
OrderedMultiDictionary, además de las que extienden las que el propio CLR
proporciona.
NUnit: Inicialmente basada en la librería JUnit de Java, NUnit 2.5 es la sexta
versión basada en xUnit. Está escrita en C# y fue totalmente rediseñada para
sacar el máximo provecho a la plataforma .NET. Se integra estupendamente tanto
con las MS Test Tools como con Resharper 5.x.
Moq: Muy útil especialmente para desarrolladores sin un gran bagaje en Mocking.
Ofrece soporte a muchas de las características de .NET como LINQ Trees
Expressions o expresiones lambda y se caracteriza por su facilidad de uso y su
forma natural de escribir stubs y mocks.
BDD specflow: Distribuida bajo licencia BSD e inspirada en Cucumber y su
comunidad, esta librería abarca las diferentes posibilidades del desarrollo
orientado a comportamiento o BDD y resalta, entre otros, su uso con aplicaciones
ASP.NET MVC.

Tipos de datos
Estructurados y definidos por el Usuario.
Hay dos clases de tipos en C#: tipos de valor y tipos de referencia. Las variables
de tipos de valor contienen directamente los datos, mientras que las variables de
los tipos de referencia almacenan referencias a los datos, lo que se conoce como
objetos. Con los tipos de referencia, es posible que dos variables hagan referencia
al mismo objeto y que, por tanto, las operaciones en una variable afecten al objeto
al que hace referencia la otra variable. Con los tipos de valor, cada variable tiene
su propia copia de los datos y no es posible que las operaciones en una variable
afecten a la otra (excepto en el caso de las variables de parámetro ref y out).
Los tipos de valor de C# se dividen en tipos simples, tipos de enumeración, tipos
de estructura y tipos de valores NULL. Los tipos de referencia de C# se dividen en
tipos de clase, tipos de interfaz, tipos de matriz y tipos delegados.
A continuación, se proporciona información general del sistema de tipos de C#.
Tipos de valor
Tipos simples
Entero con signo: sbyte, short, int,long
Entero sin signo: byte, ushort, uint,ulong
Caracteres Unicode: char
Punto flotante de IEEE: float, double
Decimal de alta precisión: decimal
Booleano: bool
Tipos de enumeración
Tipos definidos por el usuario con el formato enum E {...}
Tipos de estructura
Tipos definidos por el usuario con el formato struct S {...}
Tipos de valor que aceptan valores NULL
Extensiones de todos los demás tipos de valor con un valor null
Tipos de referencia
Tipos de clase
Clase base definitiva de todos los demás tipos: object
Cadenas Unicode: string
Tipos definidos por el usuario con el formato class C {...}
Tipos de interfaz
Tipos definidos por el usuario con el formato interface I {...}
Tipos de matriz
Unidimensional y multidimensional; por ejemplo, int[] y int[,]
Tipos delegados
Tipos definidos por el usuario con el formato delegate int D(...)
Los ocho tipos enteros proporcionan compatibilidad con valores de 8, 16, 32 y 64
bits en formato con o sin signo.
Los dos tipos de punto flotante, float y double, se representan mediante los
formatos IEC-60559 de precisión sencilla de 32 bits y de doble precisión de 64
bits, respectivamente.
El tipo decimal es un tipo de datos de 128 bits adecuado para cálculos financieros
y monetarios.
El tipo bool de C# se utiliza para representar valores booleanos; valores que son
true o false.
El procesamiento de caracteres y cadenas en C# utiliza la codificación Unicode. El
tipo char representa una unidad de código UTF-16 y el tipo string representa una
secuencia de unidades de código UTF-16.
Resume los tipos numéricos de C#.
Entero con signo
sbyte: 8 bits, de -128 a 127
short: 16 bits, de -32,768 a 32,767
int : 32 bits, de -2,147,483,648 a 2,147,483,647
long: 64 bits, de -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807
Entero sin signo
byte: 8 bits, de 0 a 255
ushort: 16 bits, de -0 a 65,535
uint: 32 bits, de -0 a 4,294,967,295
ulong: 64 bits, de -0 a 18,446,744,073,709,551,615
Punto flotante
float: 32 bits, de 1.5 × 10-45 a 3.4 × 1038, precisión de 7 dígitos
double: 64 bits, de 5.0 × 10-324 a 1.7 × 10308, precisión de 15 dígitos
Decimal
decimal: 128 bits, de al menos -7.9 × 10-28 a 7.9 × 1028, con una precisión de al
menos 28 dígitos
Los programas de C# utilizan declaraciones de tipos para crear nuevos tipos. Una
declaración de tipos especifica el nombre y los miembros del nuevo tipo. Cinco de
las categorías de tipos de C# las define el usuario: tipos de clase, tipos de
estructura, tipos de interfaz, tipos de enumeración y tipos delegados.
A tipo class define una estructura de datos que contiene miembros de datos
(campos) y miembros de función (métodos, propiedades y otros). Los tipos de
clase admiten herencia única y polimorfismo, mecanismos por los que las clases
derivadas pueden extender y especializar clases base.
Un tipo struct es similar a un tipo de clase, por el hecho de que representa una
estructura con miembros de datos y miembros de función. Sin embargo, a
diferencia de las clases, las estructuras son tipos de valor y no suelen requerir la
asignación del montón. Los tipos struct no admiten la herencia especificada por el
usuario y todos los tipos de struct se heredan implícitamente del tipo object.
Un tipo interface define un contrato como un conjunto con nombre de miembros de
función públicos. Un class o struct que implementa un interface debe proporcionar
implementaciones de miembros de función de la interfaz. Un interface puede
heredar de varias interfaces base, y un class o struct pueden implementar varias
interfaces.
Un tipo delegate representa las referencias a métodos con una lista de parámetros
determinada y un tipo de valor devuelto. Los delegados permiten tratar métodos
como entidades que se puedan asignar a variables y se puedan pasar como
parámetros. Los delegados son análogos a los tipos de función proporcionados
por los lenguajes funcionales. Son similares al concepto de punteros de función en
otros lenguajes, pero a diferencia de los punteros de función, los delegados están
orientados a objetos y presentan seguridad de tipos.
Los tipos class, struct, interface y delegate admiten parámetros genéricos,
mediante los cuales se pueden parametrizar con otros tipos.
Un tipo enum es un tipo distinto con constantes con nombre. Cada tipo enum tiene
un tipo subyacente, que debe ser uno de los ocho tipos enteros. El conjunto de
valores de un tipo enum es igual que el conjunto de valores del tipo subyacente.
C# admite matrices unidimensionales y multidimensionales de cualquier tipo. A
diferencia de los tipos enumerados anteriormente, los tipos de matriz no tienen
que ser declarados antes de usarlos. En su lugar, los tipos de matriz se crean
mediante un nombre de tipo entre corchetes. Por ejemplo, int[] es una matriz
unidimensional de int, int[,] es una matriz bidimensional de int y int[][] es una matriz
unidimensional de la matriz unidimensional de int.
Los tipos de valor NULL tampoco tienen que ser declarados antes de usarlos.
Para cada tipo de valor distinto de NULL T, existe un tipo de valor NULL
correspondiente T?, que puede tener un valor adicional, null. Por ejemplo, int? es
un tipo que puede contener cualquier número entero de 32 bits o el valor null.
El sistema de tipos de C# está unificado, de tal forma que un valor de cualquier
tipo puede tratarse como un object. Todos los tipos de C# directa o indirectamente
se derivan del tipo de clase object, y object es la clase base definitiva de todos los
tipos. Los valores de tipos de referencia se tratan como objetos mediante la
visualización de los valores como tipo object. Los valores de tipos de valor se
tratan como objetos mediante la realización de operaciones de conversión boxing
y operaciones de conversión unboxing. En el ejemplo siguiente, un valor int se
convierte en object y vuelve a int.
Cuando se convierte un valor de un tipo de valor al tipo object, se asigna una
instancia object, también denominada "box", para contener el valor, y el valor se
copia en dicho box. Por el contrario, cuando se convierte una referencia object en
un tipo de valor, se comprueba si la referencia object es un box del tipo de valor
correcto y, si la comprobación es correcta, se copia el valor del box.
El sistema de tipos unificado de C# conlleva efectivamente que los tipos de valor
pueden convertirse en objetos "a petición". Debido a la unificación, las bibliotecas
de uso general que utilizan el tipo object pueden usarse con tipos de referencia y
tipos de valor.
Hay varios tipos de variables en C#, entre otras, campos, elementos de matriz,
variables locales y parámetros. Las variables representan ubicaciones de
almacenamiento, y cada variable tiene un tipo que determina qué valores pueden
almacenarse en la variable, como se muestra a continuación.
Tipo de valor distinto a NULL
Un valor de ese tipo exacto
Tipos de valor NULL
Un valor null o un valor de ese tipo exacto
objeto
Una referencia null, una referencia a un objeto de cualquier tipo de referencia o
una referencia a un valor de conversión boxing de cualquier tipo de valor
Tipo de clase
Una referencia null, una referencia a una instancia de ese tipo de clase o una
referencia a una instancia de una clase derivada de ese tipo de clase
Tipo de interfaz
Una referencia null, una referencia a una instancia de un tipo de clase que
implementa dicho tipo de interfaz o una referencia a un valor de conversión boxing
de un tipo de valor que implementa dicho tipo de interfaz
Tipo de matriz
Una referencia null, una referencia a una instancia de ese tipo de matriz o una
referencia a una instancia de un tipo de matriz compatible
Tipo delegado
Una referencia null o una referencia a una instancia de un tipo delegado
compatible

Constantes
Las constantes son valores inmutables, y por tanto no se pueden cambiar.
const
Cuando se declara una constante con la palabra clave const, también se debe
asignar el valor. Tras esto, la constante queda bloqueada y no se puede cambiar.
Son implícitamente estáticas (static).
readonly

A diferencia de const, no requiere que se asigne el valor al mismo tiempo que se


declara. Pueden ser miembros de la instancia o miembros estáticos de la clase
(static).
Operaciones
En C#, un operador es un elemento de programa que se aplica a uno o varios
operandos en una expresión o instrucción. Los operadores que toman un
operando, como el operador de incremento (++) o new, se conocen como
operadores unarios. Los operadores que toman dos operandos, como los
operadores aritméticos (+,-,*,/) se conocen como operadores binarios . Un
operador, el operador condicional (?:), toma tres operandos y es el único operador
ternario de C#.
C# proporciona muchos operadores, que son símbolos que especifican las
operaciones (matemáticas, indización, llamada de función, etc.) que se realizan en
una expresión. Puede sobrecargar muchos operadores para cambiar su
significado al aplicarlos a un tipo definido por el usuario.
Las operaciones de tipos enteros (como ==, !=, <, >, & y |) suelen estar permitidas
en los tipos de enumeración (enum).

Tipos de operadores (Aritméticos, lógicos y relacionales)


Operadores principales
Estos son los operadores de precedencia más alta.
x.y: acceso a miembros.
x?.y: acceso a miembros condicionales nulos. Devuelve null si el operando
izquierdo se evalúa como null.
x?[y]: acceso a índices condicionales nulos. Devuelve null si el operando izquierdo
se evalúa como null.
f(x): invocación de función.
a[x]: indización de objeto agregado.
x++: incremento de postfijo. Devuelve el valor de x y, a continuación, actualiza la
ubicación de almacenamiento con el valor de x que es uno mayor (normalmente
agrega el entero 1).
x--: decremento de postfijo. Devuelve el valor de x; a continuación, actualiza la
ubicación de almacenamiento con el valor de x que es uno menos (normalmente
resta el entero 1).
new: creación de instancias de tipo.
typeof: devuelve el objeto Type que representa el operando.
checked: habilita la comprobación de desbordamiento para operaciones con
enteros.
unchecked: deshabilita la comprobación de desbordamiento para operaciones con
enteros. Este es el comportamiento predeterminado del compilador.
default(T) genera el valor predeterminado del tipo T.
delegate: declara y devuelve una instancia de delegado.
sizeof: devuelve el tamaño en bytes del operando de tipo.
->: desreferenciación del puntero combinada con acceso a miembros.
Operadores unarios
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
+x: devuelve el valor de x.
-x: negación numérica.
!x: negación lógica.
~x: complemento bit a bit.
++x: incremento de prefijo. Devuelve el valor de x después de actualizar la
ubicación de almacenamiento con el valor de x que es uno mayor (normalmente
agrega el entero 1).
--x: decremento de prefijo. Devuelve el valor de x después de actualizar la
ubicación de almacenamiento con el valor de x que es uno menos (normalmente
resta el entero 1).
(T)x: conversión de tipos.
await: espera una Task.
&x: dirección de.
*x: desreferenciación.
Operadores de multiplicación
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
x * y: multiplicación.
x / y: división. Si los operandos son enteros, el resultado es un entero que se
trunca hacia cero (por ejemplo, -7 / 2 is -3).
x % y: resto. Si los operandos son enteros, devuelve el resto de dividir x entre y. Si
q = x / y y r = x % y, entonces x = q * y + r.
Operadores aditivos
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
x + y: suma.
x – y: resta.
Operadores de desplazamiento
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
x << y: desplaza los bits a la izquierda y rellena con cero a la derecha.
x >> y: desplaza los bits a la derecha. Si el operando izquierdo es int o long, los
bits de la izquierda se rellenan con el bit de signo. Si el operando izquierdo es uint
o ulong, los bits de la izquierda se rellenan con cero.
Operadores de comprobación de tipos y relacionales
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
x < y: menor que (true si x es menor que y).
x > y: mayor que (true si x es mayor que y).
x <= y: menor o igual que.
x >= y: mayor o igual que.
is: compatibilidad de tipos. Devuelve true si el operando izquierdo evaluado se
puede convertir al tipo especificado en el operando derecho (un tipo estático).
as: conversión de tipos. Devuelve el operando izquierdo convertido al tipo
especificado por el operando derecho (un tipo estático), pero as devuelve null
donde (T)x produciría una excepción.
Operadores de igualdad
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
x == y: igualdad. De forma predeterminada, para los tipos de referencia distintos
de string, devuelve igualdad de referencia (prueba de identidad). Sin embargo, los
tipos pueden sobrecargar ==, por lo que si su intención es probar la identidad, es
mejor usar el método ReferenceEquals en object.
x != y: distinto de. Vea el comentario de ==. Si un tipo sobrecarga ==, debe
sobrecargar !=.
AND lógico (operador)
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
x & y: AND lógico o bit a bit. Por lo general puede usarlo con tipos enteros y tipos
enum.
Operador lógico XOR
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
x ^ y: XOR lógico o bit a bit. Por lo general puede usarlo con tipos enteros y tipos
enum.
Operador lógico OR (||)
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
x | y: OR lógico o bit a bit. Por lo general puede usarlo con tipos enteros y tipos
enum.
Operador condicional AND
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
x && y: AND lógico. Si el primer operando se evalúa como false, C# no evalúa el
segundo operando.
Operador condicional OR
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
x || y: OR lógico. Si el primer operando se evalúa como true, C# no evalúa el
segundo operando.
Operador de uso combinado de null
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
x ?? y: devuelve x si no es null; de lo contrario, devuelve y.
Operador condicional
Este operador tiene mayor precedencia que el de la sección siguiente y menor que
el de la anterior.
t ? x : y: si la prueba t se evalúa como true, evalúa y devuelve x; en caso contrario,
evalúa y devuelve y.
Operadores de asignación y Lambda
Estos operadores tienen mayor precedencia que los de la sección siguiente y
menor que el de la anterior.
x = y: asignación.
x += y: incremento. Agregue el valor de y al valor de x, almacene el resultado en x
y devuelva el nuevo valor. Si x designa un event, y debe ser una función adecuada
que C# agregue como un controlador de eventos.
x -= y: decremento. Reste el valor de y del valor de x, almacene el resultado en x y
devuelva el nuevo valor. Si x designa un event, y debe ser una función adecuada
que C# quite como un controlador de eventos.
x *= y: asignación de multiplicación. Multiplique el valor de y por el valor de x,
almacene el resultado en x y devuelva el nuevo valor.
x /= y: asignación de división. Divida el valor de x por el valor de y, almacene el
resultado en x y devuelva el nuevo valor.
x %= y: asignación del resto. Divida el valor de x por el valor de y, almacene el
resto en x y devuelva el nuevo valor.
x &= y: asignación de AND. AND el valor de y con el valor de x, almacene el
resultado en x y devuelva el nuevo valor.
x |= y: asignación de OR. OR el valor de y con el valor de x, almacene el resultado
en x y devuelva el nuevo valor.
x ^= y: asignación de XOR. XOR el valor de y con el valor de x, almacene el
resultado en x y devuelva el nuevo valor.
x <<= y: asignación de desplazamiento a la izquierda. Desplace el valor de x a la
izquierda y lugares, almacene el resultado en x y devuelva el nuevo valor.
x >>= y: asignación de desplazamiento a la derecha. Desplace el valor de x a la
derecha y posiciones, almacene el resultado en x y devuelva el nuevo valor.
=>: declaración lambda.

Precedencia y asociatividad de operadores


Un operando puede ser una expresión válida que se compone de código de una
longitud indeterminada y puede incluir un número cualquiera de subexpresiones.
En una expresión que contiene varios operadores, el orden de aplicación de estos
viene determinado por la prioridad de operador, la asociatividady los paréntesis.
Cada operador tiene una prioridad definida. En una expresión que contiene varios
operadores con distintos niveles de prioridad, la prioridad de los operadores
determina el orden en que estos se evalúan.
Cuando dos o más operadores con la misma prioridad están presentes en una
expresión, se evalúan según su asociatividad. Los operadores asociativos a la
izquierda se evalúan, por orden, de izquierda a derecha. Por ejemplo, x * y / z se
evalúa como (x * y) / z. Los operadores asociativos a la derecha se evalúan, por
orden, de derecha a izquierda.
Independientemente de que los operadores de una expresión sean asociativos a
la izquierda o a la derecha, los operandos de cada expresión se evalúan primero,
de izquierda a derecha.
Punteros
En C# para mantener la seguridad de tipos y la seguridad no se admite las
operaciones con punteros de manera determinada, para ello se usa la palabra
clave unsafe para definir un contexto no seguro para usar los punteros. En el
Common Language Runtime (CLR) se refieren al código no seguro como código
no comprobable lo cual no necesariamente significa que es peligroso sino que su
seguridad no se puede comprobar por el CLR, básicamente la diferencia entre el
código “unmanaged” y código definido como “unsafe” es que el primero corre fuera
del CLR mientras que el “unsafe” tiene permiso del CLR para acceder
directamente a la memoria. Es importante tomar en cuenta que el hecho de que
sea código unsafe deja al programador toda la responsabilidad del código
dejándolo a cargo de garantizar que no introduce riesgos de seguridad ni errores
de punteros.

Es importante tomar en cuenta ciertos detalles sobre el código no seguro:

Debe compilarse con la opción /unsafe Para establecer esta opción del compilador
en el entorno de desarrollo de Visual Studio:
Abra la página Propiedades del proyecto.
Haga clic en la página de propiedades Generar.
Active la casilla de verificación Permitir código no seguro.
La opción /unsafe del compilador permite compilar el código que utiliza la palabra
clave unsafe.
Para compilar in.cs en modo no seguro, ejecute: csc /unsafe in.cs
Se pueden definir como no seguros los métodos, tipos y bloques de código.
UNSAFE
Podemos usar el modificador unsafe en la declaración de un tipo o un miembro así
toda la extensión textual del tipo o del miembro se considera, por lo tanto, como
contexto no seguro.
TIPOS DE PUNTEROS
En un contexto no seguro, un tipo puede ser un tipo de puntero, un tipo de valor o
un tipo de referencia.
Un puntero puede ser tipo sbyte, byte, short, ushort, int, uint, long, ulong, char,
float, double, decimal o bool, cualquier tipo de enum, cualquier tipo de puntero
(pointer), cualquier tipo de struct definido por el usuario que sólo contenga campos
de tipos no administrados.
Para declarar varios punteros en una misma declaración debe tener en cuenta que
únicamente debe escribir * junto al tipo subyacente, no debe escribirse como
prefijo en cada nombre de puntero.

Estructuras
Al igual que las clases, los structs son estructuras de datos que pueden contener
miembros de datos y miembros de función, pero a diferencia de las clases, los
structs son tipos de valor y no requieren asignación del montón. Una variable de
un tipo de struct almacena directamente los datos del struct, mientras que una
variable de un tipo de clase almacena una referencia a un objeto asignado
dinámicamente. Los tipos struct no admiten la herencia especificada por el usuario
y todos los tipos de struct se heredan implícitamente del tipo ValueType, que a su
vez se hereda implícitamente de object.
Los structs son particularmente útiles para estructuras de datos pequeñas que
tengan semánticas de valor. Los números complejos, los puntos de un sistema de
coordenadas o los pares clave-valor de un diccionario son buenos ejemplos de
structs. El uso de un struct en lugar de una clase para estructuras de datos
pequeñas puede suponer una diferencia sustancial en el número de asignaciones
de memoria que realiza una aplicación. Por ejemplo, el siguiente programa crea e
inicializa una matriz de 100 puntos. Si Point se implementa como una clase, se
crean instancias de 101 objetos distintos: uno para la matriz y uno por cada uno de
los 100 elementos.
Los constructores structs se invocan con el operador new, similar a un constructor
de clase. Sin embargo, en lugar de asignar dinámicamente un objeto en el montón
administrado y devolver una referencia a él, un constructor de structs simplemente
devuelve el valor del struct propiamente dicho (normalmente en una ubicación
temporal en la pila) y este valor se copia luego cuando es necesario.
Con las clases, es posible que dos variables hagan referencia al mismo objeto y,
que, por tanto, las operaciones en una variable afecten al objeto al que hace
referencia la otra variable. Con los struct, cada variable tiene su propia copia de
los datos y no es posible que las operaciones en una afecten a la otra.

Funciones de entrada y salida (E/S)


Los programas de C# utilizan normalmente los servicios de entrada y salida que
ofrece la biblioteca en tiempo de ejecución de .NET Framework.

La instrucción Console.WriteLine("Hola Buenos Dias..!"); utiliza el método


WriteLine, que es uno de los métodos de salida de la clase Console de la
biblioteca en tiempo de ejecución.

Muestra el parámetro cadena en la secuencia de salida estándar seguido por una


nueva línea. Otros métodos de Console se utilizan para otras operaciones de
entrada y salida.

Dentro de la Biblioteca de clase del .Net Framework se encuentra la Clase


Console,que representa las secuencias de entrada, salida y error estándar para
las aplicaciones de modo consola en C#.

La Clase Console, dispone de los siguientes métodos:

SetCursorPosition(X,Y)---> Permite posicionarte en una coordenada especifica en


pantalla.

Read( ) --> Lee los datos que ingresa el usuario a través del Teclado con formato
texto.
ReadLine( )--> A diferencia del método anterior lee y salta una línea.

Write( )--> Escribe los datos ya sea de una(Cadena caracteres o variable) en


pantalla.

WriteLine( )--> A diferencia del método anterior escribe en pantalla y salta una
línea.

Clear( )--> Borra o limpia pantalla

Pre-Procesadores
El preprocesado es un paso previo a la compilación mediante el que es posible
controlar la forma en que se realizará ésta. El preprocesador es el módulo auxiliar
que utiliza el compilador para realizar estas tareas, y lo que finalmente el
compilador compila es el resultado de aplicar el preprocesador al fichero de texto
fuente, resultado que también es un fichero de texto.
A pesar de que C# no tenga un preprocesador de código dedicado (tal como lo
tiene C), aún podemos hacer uso de algunas instrucciones que modifican el
comportamiento del compilador, a estas palabras se les conoce como directivas.
En C# se han eliminado la mayoría de características negativas de versiones
previas, que provocaban errores difíciles de detectar (macros, directivas de
inclusión, etc.) y prácticamente sólo se usa para permitir realizar compilaciones
condicionales de código.
El preprocesador no interpreta de ninguna manera el código fuente del fichero,
sino que sólo interpreta de dicho fichero lo que se denominan directivas de
preprocesado. Estas directivas son líneas de texto del fichero fuente que se
caracterizan porque en ellas el primer carácter no blanco que aparece es una
almohadilla (carácter #)
La principal utilidad del preprocesador en C# es la de permitir determinar cuáles
regiones de código de un fichero fuente se han de compilar. Para ello, lo que se
hace es encerrar las secciones de código opcionales dentro de directivas de
compilación condicional, de modo que sólo se compilarán si determinados
identificadores de preprocesado están definidos. Es importante señalar que
cualquier definición de identificador ha de preceder a cualquier aparición de código
en el fichero fuente.
Para definir un identificador de preprocesado y que además permita que dicha
definición sólo sea válida en una compilación en concreto, se debe pasar al
compilador en su llamada la opción /d:<nombreIdentificador> (forma abreviada
de /define:<nombreIdentificador>), caso en que durante la compilación se
considerará que al principio de todos los ficheros fuente a compilar se encuentra
definido el identificador indicado. Las siguientes tres formas de llamar al
compilador son equivalentes y definen identificadores de preprocesado de
nombres PRUEBA y TRAZA durante la compilación de un fichero fuente de
nombre ejemplo.cs:
Si se trabaja con Visual Studio.NET en lugar de directamente con el compilador en
línea de comandos, entonces puede conseguir mismo efecto a través de View ->
Property Pages -> Configuration Options -> Build -> Conditional Compilation
Constants, donde nuevamente usado el punto y coma (;) o la coma (,) como
separadores, puede definir varias constantes. Para que todo funcione bien, antes
de seleccionar View ha de seleccionar en el Solution Explorer (se abre con View -
> Solution Explorer) el proyecto al que aplicar la definición de las constantes.
Finalmente, respecto al uso de #define sólo queda comentar que es posible definir
varias veces una misma directiva sin que ello provoque ningún tipo de error en el
compilador, lo que permite que podamos pasar tantos valores a la opción /d del
compilador como queramos sin temor a que entren en conflicto con identificadores
de preprocesado ya incluidos en las fuentes a compilar.
Eliminación de identificadores de preprocesado
Del mismo modo que es posible definir identificadores de preprocesado, también
es posible eliminar definiciones de este tipo de identificadores previamente
realizadas. En caso de que se intente eliminar con esta directiva un identificador
que no haya sido definido o cuya definición ya haya sido eliminada no se producirá
error alguno, sino que simplemente la directiva de eliminación será ignorada.
Al igual que ocurría con las directivas #define, no se puede incluir código fuente
antes de las directivas #undef, sino que, todo lo más, lo único que podrían
incluirse antes que ellas serían directivas de preprocesado.

Compilación condicional
Como se ha repetido varias veces a lo largo del tema, la principal utilidad del
preprocesador en C# es la de permitir la compilación de código condicional, lo que
consiste en sólo permitir que se compile determinadas regiones de código fuente
si las variables de preprocesado definidas cumplen alguna condición determinada.
Generación de avisos y errores
El preprocesador de C# también ofrece directivas que permiten generar avisos y
errores durante el proceso de preprocesado en caso de que ser interpretadas por
el preprocesador.
La directiva #warning lo que hace al ser procesada es provocar que el compilador
produzca un mensaje de aviso que siga el formato estándar usado por éste para
ello y cuyo texto descriptivo tenga el contenido indicado en <mensajeAviso>; y
#error hace lo mismo, pero provocando un mensaje de error en vez de uno de
aviso.
Usando directivas de compilación condicional se puede controlar cuando se han
de producir estos mensajes, cuando se han de procesar estas directivas. De
hecho, la principal utilidad de estas directivas es permitir controlar errores de
asignación de valores a los diferentes identificadores de preprocesado de un
código.
El preprocesador de C# considera que los mensajes asociados a directivas
#warning o #error son todo el texto que se encuentra tras el nombre de dichas
directivas y hasta el final de la línea donde éstas aparecen. Por tanto, todo
comentario que se incluya en una línea de este tipo será considerado como parte
del mensaje a mostrar, y no como comentario como tal.
Cambios en la numeración de líneas
Por defecto el compilador enumera las líneas de cada fichero fuente según el
orden normal en que estas aparecen en el mismo, y este orden es el que sigue a
la hora de informar de errores o de avisos durante la compilación. Sin embargo,
hay situaciones en las que interesa cambiar esta numeración.
El valor indicado en "<nombreFichero>" es opcional, y en caso de aparecer indica
el nombre que se ha de considerar que tiene el fichero a la hora de dar mensajes
de error.
Aunque en principio puede parecer que esta directiva es de escasa utilidad, lo
cierto es que suele venir bastante bien para la escritura de compiladores y otras
herramientas que generen código en C# a partir de código escrito en otros
lenguajes.

Marcación de regiones de código


Es posible marcar regiones de código y asociarles un nombre usando el juego de
directivas #regiony #endregion.
La utilidad que se dé a estas marcaciones depende de cada herramienta, pero en
el momento de escribir estas líneas la única herramienta disponible que hacía uso
de ellas era Visual Studio.NET, donde se usa para marcar código de modo que
desde la ventana de código podamos expandirlo y contraerlo con una única
pulsación de ratón. En concreto, en la ventana de código de Visual Studio
aparecerá un símbolo [-] junto a las regiones de código así marcadas de manera
que pulsando sobre él todo el código contenido en la región se comprimirá y será
sustituido por el nombre dado en <nombreRegión>. Tras ello, el [-] se convertirá
en un [+] y si volvemos a pulsarlo el código contraído se expandirá y recuperará su
aspecto original.

Depuración y Errores
El proceso de depuración y de corrección de los errores, siempre es
recomendable hacerlo a través del compilador, pues otorga herramientas más
agiles a través del código y evita que se formen problemas en cadena, por
cambiar, modificar y mejorar partes del programa.
Hay dos tipos básicos de configuración de compilación: Depuración y lanzamiento.
La configuración de Depuración genera un archivo ejecutable más lento y más
grande que permite una experiencia de depuración en tiempo de ejecución
interactiva y más completa. Nunca se debe enviar el archivo ejecutable de
Depuración. La configuración de Release crea un archivo ejecutable más rápido y
optimizado, adecuado para enviar (al menos desde la perspectiva del compilador).
La configuración de compilación predeterminada es Depuración.
Puede observar el proceso de compilación en la ventana de Salida, Aquí se
muestran los errores, las advertencias y las operaciones de compilación. Si tiene
errores (o advertencias por encima de un nivel configurado), se produce un error
de compilación. Se puede hacer clic en los errores y advertencias para ir a la línea
donde se produjeron.
Hay dos ventanas con pestañas en la ventana de resultados, debajo del editor de
compilación: la ventana Salida, que contiene la salida sin formato del compilador
(incluidos los mensajes de error), y la ventana Lista de errores, que proporciona
una lista, que se puede ordenar y filtrar, de todos los errores y advertencias.

Salvo que no haya realizado ninguna modificación en un código que ya se haya


compilado correctamente, es probable que tenga un error. Si no está familiarizado
con la codificación, probablemente tenga muchos. En ocasiones los errores son
obvios, como un simple error de sintaxis o nombre de variable incorrecto, y a
veces son difíciles de entender solo con un código críptico como guía. Sin
embargo, gracias a las funciones propias del compilador se puede solventar
dichos errores simplemente haciendo clic en ellos, se dirigirá directamente a la
línea y se podrá corregir dicha falla.
Una vez se han corregido la mayoría de fallas, se puede usar el compilador para
dar inicio a la depuración final, esta se inicia en un entorno de depuración para
que pueda observar su comportamiento con detalle. Mientras se está ejecutando:
la ventana Salida se sustituye por dos nuevas (en la configuración de ventanas
predeterminada), que son las ventanas con pestañas Automático/Variables
locales/Inspección y Pila de llamadas/Puntos de interrupción/Configuración de
excepciones/Salida. Estas ventanas tienen varias pestañas que permiten
inspeccionar y evaluar las variables, los subprocesos, las pilas de llamadas y otros
comportamientos de la aplicación mientras se ejecuta.
Si el código se ejecuta perfectamente el proceso de depuración fue exitoso. Si en
cambio genera fallas, quiere decir que algún error quedo sin revisar. Si bien lo
recomendable es realizar el proceso en Visual Studio, otros compiladores son
iguales de eficientes con C Sharp.

Compilación y ejecución
El proceso de compilación y ejecución se realiza usualmente utilizando algún
compilador, en el caso de C Sharp el más común es Visual Studio. Para que el
proceso pueda ser realizado de forma correcta, se suele realizar una previa
limpieza de errores, usando preprocesadores y realizando distintas depuraciones,
donde el objetivo es dejar el código lo mas limpio posible para su compilación final
y posterior ejecución. Dicho proceso variara en tiempo y dificultad en dependencia
de que tan extenso o corto sea el código en cuestión.
Compilación y ejecución de línea de comandos
Se puede compilar el programa con la línea de comandos o mediante la interfaz
de algún compilador previamente descargado.
Para realizar el proceso desde un símbolo del sistema se debe pegar el código del
procedimiento anterior en cualquier editor de texto y guardar el archivo como un
archivo de texto. Asignarle al archivo el nombre que corresponda con su función y
recordar que los archivos de código fuente de C# usan la extensión .cs.

En dependencia del sistema operativo integrado deberá ejecutar la herramienta


correspondiente para que aparezca una ventana del símbolo del sistema para
desarrolladores. Luego se procede a habilitar las compilaciones de la línea de
comandos desde una ventana estándar del símbolo del sistema.
En la ventana del símbolo del sistema, se dirigira a la carpeta que contiene el
archivo con el nombre que hemos elegido. Se escribirá entonces el comando
siguiente para compilar / Nombre del archivo /.cs.
csc /Nombre del archivo/.cs
Si el programa fue depurado y corregido correctamente no tendra ningún error de
compilación y se creará un archivo ejecutable denominado Nombre del
archivo.exe.
En la ventana del símbolo del sistema, se deberá de escribir el comando para
ejecutar el programa: Nombren del archivo y este será ejecutado para cumplir la
función que se le programo con anterioridad. Esta es la forma mas sencilla de
compilar y ejecutar en C Sharp, las variaciones de dichas herramientas
dependerán del compilador y de la longitud o complejidad del código en cuestión.
Algunos compiladores recomendados
Microsoft .NET Framework 2.0 (SDK) incluye un compilador de C#, pero no un
IDE.
Microsoft Visual Studio, IDE por excelencia de este lenguaje.
SharpDevelop, IDE libre para C# bajo licencia GNU LGPL, con una interfaz muy
similar a Microsoft Visual Studio.
Mono, es una implementación con licencia GNU GPL de todo el entorno .NET
desarrollado por Novell. Como parte de esta implementación se incluye un
compilador de C#.
DotGNU Portable.NET, de la Free Software Foundation.

Conclusión
Bibliografía
https://www.genbeta.com/desarrollo/diez-dos-librerias-open-source-
recomendables-para-net
https://www.campusmvp.es/recursos/post/historia-del-lenguaje-c-sharp-pasado-
presente-y-evolucion.aspx
https://docs.microsoft.com/es-es/dotnet/csharp/tour-of-csharp/types-and-variables
https://docs.microsoft.com/es-es/dotnet/csharp/language-reference/operators/
https://miguelangelchirinos.wordpress.com/2012/07/10/punteros-en-c/
https://programacion.net/articulo/el_lenguaje_de_programacion_c_167/4
https://docs.microsoft.com/es-es/dotnet/csharp/programming-guide/inside-a-
program/hello-world-your-first-program

También podría gustarte