Sintaxis C#
Sintaxis C#
Sintaxis C#
NET
Código básico
Sensible a mayúsculas / minúsculas
Las instrucciones terminan con ;
Los bloques de instrucciones se encierran entre llaves {}
Comentarios:
// comenta la línea
/* … */ Comenta todo lo contenido entre la apertura y el cierre (multilínea)
Bloque de contenidos plegable:
#region Descripción
#endregion
Tipos especiales
void Tipo a establecer en las funciones que no devuelven nada.
var Infiere el tipo del valor asignado. Luego es inamovible.
Modificadores de accesibilidad
public, internal, private, protected, protected internal
Nota: Los protected sólo son válidos para herencia en POO.
Algunos tipos, al asignar valor se pueden poner sufijos para especificar el tipo.
Sufijo Tipo Sufijo Tipo
U unsigned int F Float
L long D Double
UL unsigned long M Decimal
Para escribir la cadena tal cual queremos que sea, basta con antecederla de una arroba (excepto si hay dobles comillas)
p.e.: string ejemplo = @”’C:\Mi directorio’ es donde guardo todo”
Arrays
[accesibilidad] [static] tipo[ ] variable [ = new tipo[número_de_elementos] ];
[accesibilidad] [static] tipo[ , [, …]] variable [ = new tipo[numelem, [numelem, …]] ];
[accesibilidad] [static] tipo[ ] variable = {lista_de_valores};
Nota: Siempre Base 0
Operadores
Unarios: ++, -- (pre y postfijo)
Matemáticos: +, -, *, /, %
Cadena +
Relacionales ==, !=, <, >, <=, >=
Lógicos !, &, |, &&, ||
Asignación =, +=, -=, *=, /=, %=
Ternario ?:
Tipo is, typeof
Conversión: (), as
Desbordamiento: checked, unchecked (tanto para asignación de una variable como envolviendo
un bloque de código con llaves.)
Conversiones
Convert.ToTipo()
tipo.Parse() y tipo.TryParse()
variable.ToString()
(tipo) variable
variable as tipo
Enumeraciones
[accesibilidad] enum enumeración[:tipo] {
elem1 [= valor],
elem2 [= valor],
…
}
if (condición) {
V F instrucción/es;
Condición
}
Instrucción/es
if (condición) {
V F instrucción/es;
Condición
}
else {
Instrucción/es Instrucción/es instrucción/es;
}
switch (expresión) {
case valor1:
instrucción/es;
Expresión
{break | goto case valorX |
…
throw [[new] excepción] |
Valor 1 Valor 2 Valor 3 F
return [valor]} ;
Instrucción/es Instrucción/es Instrucción/es Instrucción/es
[case valor2:
case valor3 :
instrucción/es;
break;]
[default:
instrucción/es;
break;]
}
instrucción/es; instrucción/es;
V
Instrucción/es } V
Condición } while (condición)
F
Condición
F [incremento_variable_de_control]) {
V
[instrucción/es;]
Instrucción/es }
variable += salto
Recorrido colecciones
quedan
foreach (tipo variable in colección) {
F
instrucción/es;
elementos en la
colección
}
V
variable =
siguiente elemento
Instrucción/es
Nota: Puede usarse break o continue para romper la secuencia normal de cualquiera de ellos.
Instrucciones de control
using ([tipo] variable [= new tipo()]) {instrucción/es}
Nota: Sólo válido para tipos que implementen el interfaz IDisposable.
Aunque se pueden declarar las variables fuera, no es recomendable para evitar accesos que den error. Si se declara
fuera sólo lleva la variable. Si se declara se puede insanciar en la misma instrucción.
goto etiqueta1;
…
etiqueta1:
Nota: Permite salir desestructuradamente de cualquier conjunto de instrucciones (bucles incluidos) aún con varios
niveles de anidamiento, pero siempre dentro de una misma función.
Listas de argumentos
Tratamiento de excepciones
try {
instrucciones_a_ejecutar;
}
catch [(tipo_excepción [variable])] {
instrucción/es;
}
…
[finally {
instrucción/es;
}]
Lanzamiento de excepciones
Estructuras
[accesibilidad] struct nombre_estructura {
Miembros, propiedades, métodos, eventos, enumeraciones, constructores…
}
Nota: No permiten herencia (heredan de System.ValueType, que hereda de System.Object), pero sí interfaces.
La accesibilidad no puede ser protected, ya que una estructura no permite herencia.
Una estructura comparte el mismo formato que una clase, pero con alguna limitación:
Si se crean contructores, debe tener parámetros, ya que el sistema crea uno sin parámetros.
No pueden implementar destructores.
Definición de clases
[accesibilidad] [partial] class nombre_de_clase {
Miembros, propiedades, métodos, eventos, enumeraciones, constructores…
}
Nota: Las clases sólo pueden ser public o (por defecto) internal, salvo si van dentro de otra clase.
Instanciación
Propiedades
Formato simple
[accesibilidad] tipo nombre_de_propiedad { get; set; }
Formato normal
[accesibilidad] tipo nombre_de_propiedad {
[[accesibilidad] get { instrucción/es; }]
[[accesibilidad] set { instrucción/es; }]
}
Nota: Si omitimos bloque get o set pasan a ser de sólo lectura o sólo escritura.
En el bloque get debemos usar un return para devolver el dato.
En el bloque set el parámetro de entrada se llama obligatoriamente value.
Si establecemos accesibilidad, deberá ser para “cerrar” el acceso de unos de los dos, nunca para tratar de dar
mayor accesibilidad ni la misma de la propiedad.
Métodos
Son funciones normales pero accesibles desde el exterior (public o internal)
Nota: La sobrecarga de métodos en la misma clase se realiza copiando la declaración pero con diferente firma
Eventos
Debemos definir la delegada y luego el evento del tipo de la delegada.
[accesibilidad] delegate void DelegadaManejadorEvento ([lista_de_argumentos]);
[accesibilidad] event DelegadaManejadorEvento nombre_evento;
Nota: Aunque no es obligatorio, los argumentos suelen ser un sender de tipo object y un e que herede de EventArgs.
if (nombre_evento != null)
nombre_evento ([lista_de_argumentos]);
Para capturar el evento (en la clase llamante)
Constructores
[accesibilidad] [static] nombre_clase([lista_ args]) [:this([lista_ args])]
{ instrucción/es; }
Nota: La accesibilidad de constructor puede protected, ya que aunque los constructores no se heredan si lo declaramos
protected podemos acceder a él con :base, y con private no podríamos.
Un constructor static es único, sin parámetros, se invoca automáticamente la primera vez que se accede la clase y
no lleva accesibilidad.
Si hay sobrecarga, con :this se puede especificar otro constructor para que se ejecute ANTES (con herencia :base)
Destructores
public void dispose()
{ instrucción/es; }
Nota: Este método proviene normalmente de implementar el interface IDisposable. Se puede usar conjuntamente con
private void Dispose(bool disposing){…} y con GC.SuppressFinalize(this);
~nombre_clase()
{ instrucción/es; }
Nota: Sólo es recomendable implementarlo si hay objetos de código no administrado (unmanaged), por el consumo de
recursos.
El compilador lo convierte automáticamente en una sobrecarga del método interno Finalize
Propiedades
[accesibilidad] [{virtual | abstract}] tipo nombre_de_propiedad
[get { instrucción/es; }]
[set { instrucción/es; }]
}
Nota: Por defecto, NO se pueden sobrescribir.
Caso de ser declarada como abstract NO LLEVA nada más que la cabecera de declaración con get; y/o set;
[get { instrucción/es; }]
[set { instrucción/es; }]
}
Nota: La accesibilidad de la propiedad y de sus métodos get y set debe ser la misma en ambos niveles. Para cambiarla
deberemos usar new.
Con override podemos sobreescribir sólo uno de los dos métodos, get o set, dejando el otro sin tocar. Además
sealed cierra la posibilidad de sobreescritura.
La palabra clave new permite escribir la propiedad desde cero, ocultando la de la clase superior. Evita una
advertencia del compilador.
Interfaces
[accesibilidad] interface nombre_interface [: nombre_interface_base ]
}
Nota: Los contenidos NO llevan modificador de accesibilidad ni pueden ser declarados virtual.
Hashtable, ListDictionary,
HybridDictionary, Dictionary< K, V >
OrderedDictionary
StringDictionary,
Dictionary< String, String >
NameValueCollection
Genéricos de usuario
Clases con tipos parametrizados. Una vez definida los tipos son invariables.
Se definen en la declaración de la clase como “variables”, que se utilizarán dentro de la
clase para definir los tipos de los contenidos.
[accesibilidad] [partial] class nombre_de_clase <T1, T2, ...> [where T1: restricción/es …]
{
Miembros, propiedades, métodos, eventos, enumeraciones, constructores… p.e.:
public T1 Dato1 { get; set; }
public T2 Dato2 { get; set; }
public nombre_de_clase (T1 dato1Inicial, T2 dato2Inicial)
{
Dato1 = dato1Inicial;
Dato2 = dato2Inicial;
}
...
}
Nota: Pueden llevar tantos tipos como sea necesario.
Cada tipo puede llevar restricciones y se pondrá un “where” por cada tipo.
Cada tipo puede tener más de una restricción. En ese caso, se separan por comas.
public class Multiproducto<T1, T2>
where T1 : Product
where T2 : T1, IComparable<T1>, IDisposable, new()
Los tipos de restricciones son los siguientes:
where T : <interface> El tipo del argumento debe implementar el interface especificado.
where T : <clase> El tipo del argumento debe ser o heredar de la clase especificada.
where T : U El tipo del argumento debe ser o heredar del tipo especificado por U.
where T : new() El tipo del argumento debe tener un constructor público vacío. Debe ir al final.
where T : struct El tipo del argumento debe ser un tipo por valor.
where T : class El tipo del argumento debe ser un tipo por referencia.
Normalmente las clases genéricas creadas por el usuario se utilizan para crear
colecciones, pudiendo usarse los tipos parametrizados para determinar el tipo de los
contenidos de la colección y pudiendo así exponer los métodos que nos interese.
Si implementamos ICollection o IDictionary entonces podremos tener las propiedades y
métodos de colecciones y diccionarios, añadiendo así los nuestros.
Uso:
Se puede crear una variable e instanciarla, dándole como parámetro el nombre de la función que
queremos que se ejecute, llamando luego a la delegada para su ejecución.
Se le puede pasar a dicha variable una expresión Lambda (ver más adelante) para su ejecución de
la misma manera que la anterior. En ese caso no se instancia, sino que la asignación del código
crea implícitamente la instancia. Además, los parámetros que espera recibir la delegada se
ponen con un nombre para poder identificarlos en el código posterior al símbolo =>
p.e.:
Declaración
delegate float Operar(float ope1, float ope2); //Delegada
float Suma(float x, float y) { return x + y; } //Método a pasar
float Resta(float x, float y) { return x - y; } //Método a pasar
Asignación
Operar delOperacion = null;
delOperacion = new Operar(Suma); //Método a llamar
delOperacion = new Operar(Resta); //Método a llamar
o
delOperacion = ((o1, o2) => o1 + o2); //Expresión Lambda
delOperacion = ((o1, o2) => o1 - o2); //Expresión Lambda
Llamada
Resultado: " + delOperacion(x, y);
Inicializaciones
[accesibilidad] tipo variable = new tipo([argumentos])
{ propiedad = valor, propiedad= valor, …};
Nota: Si el tipo tiene constructores parametrizados, se pueden usar y asignar el resto con la inicialización.
Inferencia de tipos
var variable = valor_inicial;
Nota: La inferencia de tipos NO funciona a nivel de clase, sólo en variables locales en funciones, etc.
Tipos anónimos
Es una mezcla entre Inicializaciones e Inferencia:
Eventos
En el caso de los eventos, se da la posibilidad de simplificar la asignación de los
manejadores
Asignación tradicional
button1.Click += new RoutedEventHandler(button1_Click);
Delegada automática
button1.Click += button1_Click;
Delegada incializada
button1.Click += delegate(object sender, RoutedEventArgs e) {código};
Expresión Lambda (ver más abajo)
button1.Click += (sender, e) => {código};
Func y Action
Permiten abreviar y simplificar el uso de delegadas, evitando tener que crear la delegada
en sí misma, con lo que permiten generar llamadas usando delegadas creadas “al vuelo”.