Documentos de Académico
Documentos de Profesional
Documentos de Cultura
28/01/2021
Tiempo de lectura: 14 minutos
o
o
Arquitectura de .NET
Los programas de C# se ejecutan en .NET, un sistema de ejecución virtual
denominado Common Language Runtime (CLR) y un conjunto de bibliotecas de
clases. CLR es la implementación de Microsoft del estándar internacional
Common Language Infrastructure (CLI). CLI es la base para crear entornos de
ejecución y desarrollo en los que los lenguajes y las bibliotecas funcionan juntos
sin problemas.
Hola a todos
El programa "Hola mundo" tradicionalmente se usa para presentar un lenguaje
de programación. En este caso, se usa C#:
C#Copiar
Ejecutar
using System;
class Hello
{
static void Main()
{
Console.WriteLine("Hello, World");
}
}
Tipos y variables
Hay dos clases de tipos en C#: tipos de valor y tipos de referencia. Las variables
de tipos de valor contienen directamente sus datos. Las variables de 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. 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 para las variables de
parámetro ref y out).
Tipos de valor
o Tipos simples
Entero con signo: sbyte, short, int, long
Entero sin signo: byte, ushort, uint, ulong
Caracteres Unicode: char, que representa una unidad de
código UTF-16
Punto flotante binario IEEE: float, double
Punto flotante decimal de alta precisión : decimal
Booleano: bool, que representa valores booleanos, valores
que son true o false
o Tipos de enumeración
Tipos definidos por el usuario con el formato enum E
{...}. 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.
o Tipos de estructura
Tipos definidos por el usuario con el formato struct S
{...}
o Tipos de valores que aceptan valores NULL
Extensiones de todos los demás tipos de valor con un
valor null
o Tipos de valor de tupla
Tipos definidos por el usuario con el formato (T1, T2, ...)
Tipos de referencia
o Tipos de clase
Clase base definitiva de todos los demás tipos: object
Cadenas Unicode: string, que representa una secuencia de
unidades de código UTF-16
Tipos definidos por el usuario con el formato class C {...}
o Tipos de interfaz
Tipos definidos por el usuario con el formato interface I
{...}
o Tipos de matriz
Unidimensional, multidimensional y escalonada. Por
ejemplo, int[], int[,] y int[][].
o Tipos delegados
Tipos definidos por el usuario con el formato delegate int
D(...)
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. Seis
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, tipos de delegado y tipos de
valor de tupla.
C#Copiar
int i = 123;
object o = i; // Boxing
int j = (int)o; // Unboxing
Hay varios tipos de variables en C#, entre otras, campos, elementos de matriz,
variables locales y parámetros. Las variables representan ubicaciones de
almacenamiento. Cada variable tiene un tipo que determina qué valores se
pueden almacenar en ella, como se muestra a continuación.
C#Copiar
using System;
namespace Acme.Collections
{
public class Stack<T>
{
Entry _top;
public T Pop()
{
if (_top == null)
{
throw new InvalidOperationException();
}
T result = _top.Data;
_top = _top.Next;
return result;
}
class Entry
{
public Entry Next { get; set; }
public T Data { get; set; }
Nota
Una pila es una colección de tipo "el primero que entra es el último que sale"
(FILO). Los elementos nuevos se agregan a la parte superior de la pila. Cuando
se quita un elemento, se quita de la parte superior de la pila.
C#Copiar
using System;
using Acme.Collections;
class Example
{
public static void Main()
{
var s = new Stack<int>();
s.Push(1); // stack contains 1
s.Push(10); // stack contains 1, 10
s.Push(100); // stack contains 1, 10, 100
Console.WriteLine(s.Pop()); // stack contains 1, 10
Console.WriteLine(s.Pop()); // stack contains 1
Console.WriteLine(s.Pop()); // stack is empty
}
}
Tipos y miembros
06/08/2020
Tiempo de lectura: 6 minutos
o
Clases y objetos
Las clases son los tipos más fundamentales de C#. Una clase es una estructura
de datos que combina estados (campos) y acciones (métodos y otros miembros
de función) en una sola unidad. Una clase proporciona una definición
para instancias de la clase, también conocidas como objetos. Las clases
admiten herencia y polimorfismo, mecanismos por los que las clases
derivadas pueden extender y especializar clases base.
C#Copiar
public class Point
{
public int X { get; }
public int Y { get; }
C#Copiar
var p1 = new Point(0, 0);
var p2 = new Point(10, 20);
Parámetros de tipo
C#Copiar
public class Pair<TFirst, TSecond>
{
public TFirst First { get; }
public TSecond Second { get; }
C#Copiar
var pair = new Pair<int, string>(1, "two");
int i = pair.First; // TFirst int
string s = pair.Second; // TSecond string
Clases base
C#Copiar
public class Point3D : Point
{
public int Z { get; set; }
Una clase hereda a los miembros de su clase base. La herencia significa que una
clase contiene implícitamente casi todos los miembros de su clase base. Una
clase no hereda la instancia, los constructores estáticos ni el finalizador. Una
clase derivada puede agregar nuevos miembros a aquellos de los que hereda,
pero no puede quitar la definición de un miembro heredado. En el ejemplo
anterior, Point3D hereda los miembros X y Y de Point, y cada instancia
de Point3D contiene tres miembros: X, Y y Z.
Existe una conversión implícita de un tipo de clase a cualquiera de sus tipos de
clase base. Una variable de un tipo de clase puede hacer referencia a una
instancia de esa clase o a una instancia de cualquier clase derivada. Por ejemplo,
dadas las declaraciones de clase anteriores, una variable de tipo Point puede
hacer referencia a una instancia de Point o Point3D:
C#Copiar
Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);
Estructuras
Las clases definen tipos que admiten la herencia y el polimorfismo. Permiten
crear comportamientos sofisticados basados en jerarquías de clases
derivadas. Por el contrario, los tipos *struct _ son tipos más sencillos cuyo
propósito principal es almacenar valores de datos. Dichos tipos struct no
pueden declarar un tipo base; se derivan implícitamente
de System.ValueType. No se pueden derivar otros tipos de struct a partir de un
tipo de struct. Están sellados implícitamente.
C#Copiar
public struct Point
{
public double X { get; }
public double Y { get; }
Interfaces
Una interfaz define un contrato que se puede implementar mediante clases y
estructuras. Una interfaz puede contener métodos, propiedades, eventos e
indexadores. Normalmente, una interfaz no proporciona implementaciones de
los miembros que define, sino que simplemente especifica los miembros que se
deben proporcionar mediante clases o estructuras que implementan la interfaz.
C#Copiar
interface IControl
{
void Paint();
}
interface ITextBox : IControl
{
void SetText(string text);
}
C#Copiar
interface IDataBound
{
void Bind(Binder b);
}
C#Copiar
EditBox editBox = new EditBox();
IControl control = editBox;
IDataBound dataBound = editBox;
Enumeraciones
Un tipo de enumeración define un conjunto de valores constantes. En el
elemento enum siguiente se declaran constantes que definen diferentes verduras
de raíz:
C#Copiar
public enum SomeRootVegetable
{
HorseRadish,
Radish,
Turnip
}
C#Copiar
[Flags]
public enum Seasons
{
None = 0,
Summer = 1,
Autumn = 2,
Winter = 4,
Spring = 8,
All = Summer | Autumn | Winter | Spring
}
C#Copiar
var turnip = SomeRootVegetable.Turnip;
C#Copiar
int? optionalInt = default;
optionalInt = 5;
string? optionalText = default;
optionalText = "Hello World.";
Tuplas
C# admite _ tuplas*, lo que proporciona una sintaxis concisa para agrupar varios
elementos de datos en una estructura de datos ligera. Puede crear una instancia
de una tupla declarando los tipos y los nombres de los miembros entre ( y ),
como se muestra en el ejemplo siguiente:
C#Copiar
(double Sum, int Count) t2 = (4.5, 3);
Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
// Output:
// Sum of 3 elements is 4.5.
Las tuplas proporcionan una alternativa para la estructura de datos con varios
miembros sin usar los bloques de creación que se describen en el siguiente
artículo.
o
o
Miembros
Los miembros de una class son estáticos o de instancia. Los miembros estáticos
pertenecen a clases y los miembros de instancia pertenecen a objetos
(instancias de clases).
Accesibilidad
Cada miembro de una clase tiene asociada una accesibilidad, que controla las
regiones del texto del programa que pueden acceder al miembro. Existen seis
formas de accesibilidad posibles. A continuación se resumen los modificadores
de acceso.
Campos
Un campo es una variable que está asociada con una clase o a una instancia de
una clase.
C#Copiar
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
public byte R;
public byte G;
public byte B;
Métodos
Un método es un miembro que implementa un cálculo o una acción que puede
realizar un objeto o una clase. A los métodos estáticos se accede a través de la
clase. A los métodos de instancia se accede a través de instancias de la clase.
Los métodos pueden tener una lista de parámetros, los cuales representan
valores o referencias a variables que se pasan al método. Los métodos tienen
un tipo de valor devuelto, el cual especifica el tipo del valor calculado y devuelto
por el método. El tipo de valor devuelto de un método es void si no devuelve un
valor.
Al igual que los tipos, los métodos también pueden tener un conjunto de
parámetros de tipo, para lo cuales se deben especificar argumentos de tipo
cuando se llama al método. A diferencia de los tipos, los argumentos de tipo a
menudo se pueden deducir de los argumentos de una llamada al método y no
es necesario proporcionarlos explícitamente.
C#Copiar
public override string ToString() => "This is an object";
Parámetros
C#Copiar
static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
C#Copiar
static void Divide(int x, int y, out int result, out int remainder)
{
result = x / y;
remainder = x % y;
}
C#Copiar
public class Console
{
public static void Write(string fmt, params object[] args) { }
public static void WriteLine(string fmt, params object[] args) { }
// ...
}
C#Copiar
int x, y, z;
x = 3;
y = 4;
z = 5;
Console.WriteLine("x={0} y={1} z={2}", x, y, z);
C#Copiar
int x = 3, y = 4, z = 5;
C#Copiar
class Squares
{
public static void WriteSquares()
{
int i = 0;
int j;
while (i < 10)
{
j = i * i;
Console.WriteLine($"{i} x {i} = {j}");
i = i + 1;
}
}
}
C#Copiar
class Entity
{
static int s_nextSerialNo;
int _serialNo;
public Entity()
{
_serialNo = s_nextSerialNo++;
}
C#Copiar
Entity.SetNextSerialNo(1000);
Entity e1 = new Entity();
Entity e2 = new Entity();
Console.WriteLine(e1.GetSerialNo()); // Outputs "1000"
Console.WriteLine(e2.GetSerialNo()); // Outputs "1001"
Console.WriteLine(Entity.GetNextSerialNo()); // Outputs "1002"
C#Copiar
public abstract class Expression
{
public abstract double Evaluate(Dictionary<string, object> vars);
}
C#Copiar
Expression e = new Operation(
new VariableReference("x"),
'+',
new Constant(3));
C#Copiar
Expression e = new Operation(
new VariableReference("x"),
'*',
new Operation(
new VariableReference("y"),
'+',
new Constant(2)
)
);
Dictionary<string, object> vars = new Dictionary<string, object>();
vars["x"] = 3;
vars["y"] = 5;
Console.WriteLine(e.Evaluate(vars)); // "21"
vars["x"] = 1.5;
vars["y"] = 9;
Console.WriteLine(e.Evaluate(vars)); // "16.5"
Sobrecarga de métodos
C#Copiar
class OverloadingExample
{
static void F() => Console.WriteLine("F()");
static void F(object x) => Console.WriteLine("F(object)");
static void F(int x) => Console.WriteLine("F(int)");
static void F(double x) => Console.WriteLine("F(double)");
static void F<T>(T x) => Console.WriteLine("F<T>(T)");
static void F(double x, double y) => Console.WriteLine("F(double,
double)");
C#Copiar
public class MyList<T>
{
const int DefaultCapacity = 4;
T[] _items;
int _count;
Constructores
C#Copiar
MyList<string> list1 = new MyList<string>();
MyList<string> list2 = new MyList<string>(10);
Propiedades
Una propiedad se declara como un campo, salvo que la declaración finaliza con
un descriptor de acceso get o un descriptor de acceso set escrito entre los
delimitadores { y } en lugar de finalizar en un punto y coma. Una propiedad que
tiene un descriptor de acceso get y un descriptor de acceso set es
una propiedad de lectura y escritura. Una propiedad que solo tiene un descriptor
de acceso get es una propiedad de solo lectura. Una propiedad que solo tiene un
descriptor de acceso set es una propiedad de solo escritura.
C#Copiar
MyList<string> names = new MyList<string>();
names.Capacity = 100; // Invokes set accessor
int i = names.Count; // Invokes get accessor
int j = names.Capacity; // Invokes get accessor
Indexadores
C#Copiar
MyList<string> names = new MyList<string>();
names.Add("Liz");
names.Add("Martha");
names.Add("Beth");
for (int i = 0; i < names.Count; i++)
{
string s = names[i];
names[i] = s.ToUpper();
}
Eventos
C#Copiar
class EventExample
{
static int s_changeCount;
Operadores
C#Copiar
MyList<int> a = new MyList<int>();
a.Add(1);
a.Add(2);
MyList<int> b = new MyList<int>();
b.Add(1);
b.Add(2);
Console.WriteLine(a == b); // Outputs "True"
b.Add(3);
Console.WriteLine(a == b); // Outputs "False"
Finalizadores
Expresiones
Las expresiones se construyen con operandos y operadores. Los operadores de
una expresión indican qué operaciones se aplican a los operandos. Ejemplos de
operadores incluyen +, -, *, / y new. Algunos ejemplos de operandos son literales,
campos, variables locales y expresiones.
Instrucciones
Las acciones de un programa se expresan mediante instrucciones. C# admite
varios tipos de instrucciones diferentes, varias de las cuales se definen en
términos de instrucciones insertadas.
Un bloque permite que se escriban varias instrucciones en contextos
donde se permite una única instrucción. Un bloque se compone de una
lista de instrucciones escritas entre los delimitadores { y }.
Las instrucciones de declaración se usan para declarar variables locales y
constantes.
Las instrucciones de expresión se usan para evaluar expresiones. Las
expresiones que pueden usarse como instrucciones incluyen invocaciones
de método, asignaciones de objetos mediante el operador new,
asignaciones mediante = y los operadores de asignación compuestos,
operaciones de incremento y decremento mediante los operadores +
+ y -- y expresiones await.
Las instrucciones de selección se usan para seleccionar una de varias
instrucciones posibles para su ejecución en función del valor de alguna
expresión. Este grupo contiene las instrucciones if y switch.
Las instrucciones de iteración se usan para ejecutar una instrucción
insertada de forma repetida. Este grupo contiene las
instrucciones while, do, for y foreach.
Las instrucciones de salto se usan para transferir el control. Este grupo
contiene las instrucciones break, continue, goto, throw, return y yield.
La instrucción try... catch se usa para detectar excepciones que se
producen durante la ejecución de un bloque, y la
instrucción try... finally se usa para especificar el código de finalización
que siempre se ejecuta, tanto si se ha producido una excepción como si
no.
Las instrucciones checked y unchecked sirven para controlar el contexto de
comprobación de desbordamiento para conversiones y operaciones
aritméticas de tipo integral.
La instrucción lock se usa para obtener el bloqueo de exclusión mutua
para un objeto determinado, ejecutar una instrucción y, luego, liberar el
bloqueo.
La instrucción using se usa para obtener un recurso, ejecutar una
instrucción y, luego, eliminar dicho recurso.
Matrices
C#Copiar
int[] a = new int[10];
for (int i = 0; i < a.Length; i++)
{
a[i] = i * i;
}
for (int i = 0; i < a.Length; i++)
{
Console.WriteLine($"a[{i}] = {a[i]}");
}
C#Copiar
int[] a1 = new int[10];
int[,] a2 = new int[10, 5];
int[,,] a3 = new int[10, 5, 2];
C#Copiar
int[][] a = new int[3][];
a[0] = new int[10];
a[1] = new int[5];
a[2] = new int[20];
La primera línea crea una matriz con tres elementos, cada uno de tipo int[] y
cada uno con un valor inicial de null. Las líneas siguientes inicializan entonces
los tres elementos con referencias a instancias de matriz individuales de
longitud variable.
C#Copiar
int[] a = new int[] { 1, 2, 3 };
C#Copiar
int[] a = { 1, 2, 3 };
C#Copiar
int[] t = new int[3];
t[0] = 1;
t[1] = 2;
t[2] = 3;
int[] a = t;
C#Copiar
foreach (int item in a)
{
Console.WriteLine(item);
}
Interpolación de cadenas
La interpolación de cadenas de C# le permite dar formato a las cadenas
mediante la definición de expresiones cuyos resultados se colocan en una
cadena de formato. Por ejemplo, en el ejemplo siguiente se imprime la
temperatura de un día determinado a partir de un conjunto de datos
meteorológicos:
C#Copiar
Console.WriteLine($"The low and high temperature on {weatherData.Date:MM-DD-
YYYY}");
Console.WriteLine($" was {weatherData.LowTemp} and
{weatherData.HighTemp}.");
// Output (similar to):
// The low and high temperature on 08-11-2020
// was 5 and 30.
Detección de patrones
El lenguaje C# proporciona expresiones de *coincidencia de patrones _ para
consultar el estado de un objeto y ejecutar código basado en dicho
estado. Puede inspeccionar los tipos y los valores de las propiedades y los
campos para determinar qué acción se debe realizar. La expresión switch es la
expresión primaria para la coincidencia de patrones.
C#Copiar
delegate double Function(double x);
class Multiplier
{
double _factor;
class DelegateExample
{
static double[] Apply(double[] a, Function f)
{
var result = new double[a.Length];
for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
return result;
}
Los delegados también se pueden crear mediante funciones anónimas, que son
"métodos insertados" que se crean al declararlos. Las funciones anónimas
pueden ver las variables locales de los métodos adyacentes. En el ejemplo
siguiente no se crea una clase:
C#Copiar
double[] doubles = Apply(a, (double x) => x * 2.0);
async y await
C# admite programas asincrónicos con dos palabras clave: async y await. Puede
agregar el modificador async a una declaración de método para declarar que
dicho método es asincrónico. El operador await indica al compilador que espere
de forma asincrónica a que finalice un resultado. El control se devuelve al autor
de la llamada, y el método devuelve una estructura que administra el estado del
trabajo asincrónico. Normalmente, la estructura es un
elemento System.Threading.Tasks.Task<TResult>, pero puede ser cualquier tipo
que admita el patrón awaiter. Estas características permiten escribir código que
se lee como su homólogo sincrónico, pero que se ejecuta de forma
asincrónica. Por ejemplo, el código siguiente descarga la página principal
de Microsoft Docs:
C#Copiar
public async Task<int> RetrieveDocsHomePage()
{
var client = new HttpClient();
byte[] content = await
client.GetByteArrayAsync("https://docs.microsoft.com/");
Console.WriteLine($"{nameof(RetrieveDocsHomePage)}: Finished
downloading.");
return content.Length;
}
Atributos
Los tipos, los miembros y otras entidades en un programa de C # admiten
modificadores que controlan ciertos aspectos de su comportamiento. Por
ejemplo, la accesibilidad de un método se controla mediante los
modificadores public, protected, internal y private. C # generaliza esta
funcionalidad de manera que los tipos de información declarativa definidos por
el usuario se puedan adjuntar a las entidades del programa y recuperarse en
tiempo de ejecución. Los programas especifican esta información declarativa
adicional mediante la definición y el uso de _ atributos*.
C#Copiar
public class HelpAttribute : Attribute
{
string _url;
string _topic;
C#Copiar
[Help("https://docs.microsoft.com/dotnet/csharp/tour-of-csharp/features")]
public class Widget
{
[Help("https://docs.microsoft.com/dotnet/csharp/tour-of-csharp/features",
Topic = "Display")]
public void Display(string text) { }
}
C#Copiar
Type widgetType = typeof(Widget);
object[] widgetClassAttributes =
widgetType.GetCustomAttributes(typeof(HelpAttribute), false);
if (widgetClassAttributes.Length > 0)
{
HelpAttribute attr = (HelpAttribute)widgetClassAttributes[0];
Console.WriteLine($"Widget class help URL : {attr.Url} - Related topic :
{attr.Topic}");
}
System.Reflection.MethodInfo displayMethod =
widgetType.GetMethod(nameof(Widget.Display));
object[] displayMethodAttributes =
displayMethod.GetCustomAttributes(typeof(HelpAttribute), false);
if (displayMethodAttributes.Length > 0)
{
HelpAttribute attr = (HelpAttribute)displayMethodAttributes[0];
Console.WriteLine($"Display method help URL : {attr.Url} - Related
topic : {attr.Topic}");
}