La plataforma .NET
La plataforma de Microsoft de arriba abajo: el estándar y su motor de ejecución, los ensamblados y el código intermedio, las versiones que hay que distinguir, los dos lenguajes principales con sus elementos y estructuras, el acceso a datos y el desarrollo web con ASP.NET.
CLI, CLR y el código intermedio
La plataforma .NET está descrita por un estándar, no por un producto, y de ese estándar salen todas las siglas del tema. Conviene fijarlas de una en una porque se preguntan casi siempre en forma de definición suelta.
| Sigla | Nombre | Qué es |
|---|---|---|
| CLI | Common Language Infrastructure | El estándar completo de la plataforma: formato de los ejecutables, sistema de tipos y entorno de ejecución |
| VES | Virtual Execution System | El entorno de ejecución que describe el estándar. Es la especificación, no el programa |
| CLR | Common Language Runtime | La implementación real de ese entorno, es decir, el motor que ejecuta. Es el equivalente de la máquina virtual de Java |
| CIL | Common Intermediate Language | El código intermedio al que compilan todos los lenguajes de la plataforma. Antes se llamaba MSIL. Es el equivalente del bytecode |
| CTS | Common Type System | El sistema de tipos común: clases, tipos por valor, interfaces y delegados, definidos una vez para todos los lenguajes |
| CLS | Common Language Specification | El subconjunto de reglas que un lenguaje debe cumplir para poder convivir con los demás en la plataforma |
El motor de ejecución hace mucho más que interpretar instrucciones: carga en memoria los tipos que van haciendo falta, compila el código intermedio a código nativo, gestiona los hilos, propaga las excepciones, libera la memoria con su recolector de basura y aplica las comprobaciones de seguridad. Es exactamente el mismo reparto de tareas que en el lado de Java, con otros nombres.
Queda una sigla más, el GAC (Global Assembly Cache), un almacén común de la máquina donde se registran bibliotecas compartidas por varias aplicaciones, con una función parecida a la del classpath. Importa un matiz: el GAC pertenece a .NET Framework, el .NET moderno no lo usa y cada aplicación lleva consigo sus propias dependencias.
CTS y CLS se confunden sin remedio si no se separan así: el CTS dice qué tipos existen, el CLS dice qué parte de esos tipos puede usar un lenguaje para que otro lenguaje lo entienda. Uno describe, el otro restringe.
Para el examen
CLI: el estándar
CLR: el motor de ejecución; equivale a la JVM
CIL: el código intermedio, antes MSIL; equivale al bytecode
CTS y CLS: el sistema de tipos común y las reglas mínimas para que los lenguajes convivan
Ensamblados, compilación y las versiones de .NET
AMPLIADO (el enunciado oficial exige la plataforma completa, y este apartado del documento de origen no llevaba marca). Un ensamblado es la unidad de despliegue y de versión de .NET: el fichero .dll o .exe que se genera al compilar. Dentro no hay código nativo, sino código intermedio acompañado de metadatos que describen los tipos que contiene, de un manifiesto con su nombre, su versión y sus dependencias, y de los recursos que necesite.
La compilación ocurre en dos tiempos, igual que en Java. Primero el compilador de cada lenguaje traduce el fuente a código intermedio y produce el ensamblado. Después, en ejecución, el compilador justo a tiempo (JIT) traduce ese código intermedio al código nativo de la máquina concreta donde se está ejecutando. De ahí sale la propiedad más citada de la plataforma: como el paso de C#, de VB.NET o de F# a código intermedio ya está hecho, todos los lenguajes acaban siendo el mismo por debajo y pueden usarse entre sí sin ninguna pasarela.
AMPLIADO. Las versiones de .NET son un lío histórico que se pregunta con frecuencia, y se aclara en tres pasos.
| Producto | Cuándo | Qué lo caracteriza |
|---|---|---|
| .NET Framework | Desde 2002 | El original. Solo Windows, ligado al sistema operativo. Sigue mantenido, pero ya no recibe funcionalidad nueva |
| .NET Core | Desde 2016 | Reescritura multiplataforma, de código abierto, modular y con despliegue independiente del sistema |
| .NET (a secas) | Desde 2020 | La convergencia de los dos anteriores en un único producto, numerado 5, 6, 7 y siguientes |
Dos consecuencias prácticas. La primera: una aplicación nueva se escribe sobre el .NET moderno, y .NET Framework solo aparece en el mantenimiento de aplicaciones antiguas atadas a Windows. La segunda: la numeración del producto y la del motor de ejecución no van del brazo, así que citar «la versión de .NET» no dice por sí solo qué motor hay debajo.
.NET Core no es una versión reducida de .NET Framework, ni .NET 5 la continuación de .NET Framework 4.8. Son dos líneas distintas que confluyeron en 2020 en un único producto multiplataforma y de código abierto.
Para el examen
Ensamblado: la unidad de despliegue: .dll o .exe
Qué contiene: código intermedio más metadatos y manifiesto
.NET Framework: 2002, solo Windows
.NET Core: 2016, multiplataforma
.NET a secas: desde 2020, unifica los dos
C# y VB.NET, y los tipos que declaran
AMPLIADO en su primera mitad. La plataforma admite varios lenguajes, y dos concentran casi todo su uso. C# es el principal: su sintaxis viene de la familia de C, C++ y Java, delimita los bloques con llaves, termina las sentencias con punto y coma y distingue mayúsculas de minúsculas. VB.NET continúa la tradición de Visual Basic: delimita los bloques con palabras («If» y «End If», «Sub» y «End Sub»), no usa punto y coma y no distingue mayúsculas de minúsculas. Los dos compilan al mismo código intermedio y tienen la misma potencia; la diferencia es de sintaxis y de uso real, ampliamente a favor de C#.
Sobre esa base, los tipos que se pueden declarar son cuatro, y distinguirlos es lo que de verdad se pregunta.
| Tipo | Qué es | Herencia |
|---|---|---|
| Clase | La plantilla habitual, con campos y métodos, de la que se crean objetos. Se maneja por referencia | Hereda de otra clase e implementa interfaces |
| Estructura | Un agrupador de datos, parecido a la clase, pero que se maneja por valor. También admite métodos | No hereda, aunque sí puede implementar interfaces |
| Módulo | Un contenedor de utilidades cuyos miembros son todos compartidos. Existe una única copia durante toda la vida del programa y no hay que crearla | Ni hereda ni implementa interfaces |
| Interfaz | Un contrato de operaciones sin cuerpo, que las clases se comprometen a cumplir | Puede heredar de otras interfaces |
Una clase se puede además marcar como parcial, lo que permite repartir su declaración entre varios ficheros y que el compilador los reúna. Es lo que hace posible que una herramienta genere automáticamente una mitad del código mientras la otra mitad la escribe una persona, sin que se pisen.
El otro elemento característico es la propiedad. Una propiedad se usa desde fuera como si fuera un campo, con una simple asignación o lectura, pero por dentro ejecuta un bloque de lectura y otro de escritura. No rompe la encapsulación: la conserva y además la disimula, porque permite validar, convertir o registrar sin que quien la usa tenga que llamar a un método. Si solo se declara uno de los dos bloques, la propiedad queda de solo lectura o de solo escritura.
public class Alumno
{
private string _modalidad;
// se usa como un campo, pero controla lo que entra
public string Modalidad
{
get { return _modalidad; }
set
{
if (value != "largo" && value != "mediano" && value != "express")
throw new ArgumentException("Modalidad no válida");
_modalidad = value;
}
}
}
var alumno = new Alumno();
alumno.Modalidad = "express"; // por dentro pasa por el bloque setPara el examen
Clase: tipo por referencia
Estructura: tipo por valor; no hereda
Módulo e interfaz: miembros compartidos y contrato
Propiedad: se usa como un campo, pero ejecuta sus bloques de lectura y escritura
Herencia, interfaces y modificadores
Los mecanismos de la orientación a objetos son los mismos que en Java, pero las palabras cambian, y ahí está el trabajo. En VB.NET, Inherits expresa la herencia, tanto entre clases como entre interfaces, e Implements expresa que una clase cumple una interfaz. Dentro de un objeto, Me es la referencia a la instancia actual y MyBase la referencia a la clase de la que se hereda.
| Idea | En VB.NET | En C# | Equivalente en Java |
|---|---|---|---|
| La instancia actual | Me | this | this |
| La clase padre | MyBase | base | super |
| Clase que hay que heredar obligatoriamente | MustInherit | abstract | abstract |
| Clase de la que nadie puede heredar | NotInheritable | sealed | final |
| Método que se puede sobrescribir | Overridable | virtual | Cualquier método, salvo que sea final |
| Método que hay que sobrescribir | MustOverride | abstract | abstract |
| Método que no se puede sobrescribir | NotOverridable | sealed | final |
| Miembro que pertenece al tipo y no al objeto | Shared | static | static |
Hay una diferencia de fondo con Java que conviene subrayar. En Java cualquier método se puede sobrescribir salvo que se declare final; en .NET ocurre al revés: un método solo se puede sobrescribir si su autor lo ha permitido expresamente, y quien lo sobrescribe está obligado a decirlo con la palabra reservada correspondiente. La plataforma prefiere que las dos partes lo declaren en voz alta.
Además de clases, estructuras, interfaces y enumeraciones, .NET tiene un tipo pensado para transportar datos, el registro (record), que se comporta como una fila de una tabla, y un mecanismo de eventos: un miembro que se declara como evento, se dispara desde el código y al que otras partes del programa se suscriben para reaccionar cuando ocurra.
Para el examen
Me y MyBase: this y super
MustInherit y NotInheritable: abstract y sealed o final
Shared: static
Sobrescritura: en .NET solo si se declaró virtual u Overridable; en Java, salvo que sea final
Estructuras de control
Las estructuras de control son las de cualquier lenguaje imperativo, y lo único que cambia respecto a Java es la forma de escribirlas. En VB.NET el bloque no se abre con una llave, sino que se cierra con una palabra: a If le corresponde End If, a Sub le corresponde End Sub y así con todas.
| Para qué | En VB.NET | En Java |
|---|---|---|
| Decidir | If ... Then / ElseIf / Else / End If | if / else if / else |
| Decidir entre varios valores | Select Case / Case / Case Else / End Select | switch / case / default |
| Repetir comprobando antes | While ... End While | while |
| Repetir comprobando al final | Do ... Loop Until, o Do While ... Loop | do-while |
| Repetir un número de veces | For ... To ... Next | for |
| Recorrer una colección | For Each ... In ... Next | for-each |
| Salir de un bucle | Exit For | break |
| Controlar errores | Try / Catch / Finally / End Try | try / catch / finally |
' cuántos temas quedan por repasar
If pendientes = 0 Then
mensaje = "No queda nada por repasar."
ElseIf pendientes = 1 Then
mensaje = "Queda 1 tema por repasar."
Else
mensaje = $"Quedan {pendientes} temas por repasar."
End If
' recorrer la lista de subtemas fallados
For Each subtema As String In fallados
programarRepaso(subtema)
NextLos métodos también se parten en dos según devuelvan o no un valor: los que no devuelven nada se declaran como procedimiento y los que sí, como función. En Java esa distinción no existe como tal, porque todo son métodos y lo que cambia es que el tipo de retorno sea void o no.
Para el examen
Cierre de bloques en VB.NET: con palabras: End If, End Sub
Select Case: equivale al switch
Sub frente a Function: el procedimiento no devuelve; la función sí
Acceso a datos: ADO.NET, Entity Framework y LINQ
El acceso a datos de .NET repite la misma pareja de niveles que el lado de Java, y esa correspondencia es lo que hace fácil el apartado.
| Pieza | Qué es | Su equivalente en Java |
|---|---|---|
| ADO.NET | La API de bajo nivel: conexión, comando, parámetros y lectura del resultado, con SQL escrito a mano | JDBC |
| Entity Framework | El ORM de la plataforma: la correspondencia entre clases y tablas, con el SQL generado por la biblioteca | JPA con Hibernate |
| LINQ | Un lenguaje de consulta integrado en el propio lenguaje de programación | JPQL, aunque LINQ va más allá |
Entity Framework se incorporó a la plataforma a partir de la versión 3.5 y funciona igual que cualquier ORM: la aplicación trabaja con objetos, el ORM traduce a SQL y el programador deja de escribir sentencias. Existe además NHibernate, que es la traslación a .NET del Hibernate del mundo Java, y que se cita a menudo como su alternativa.
LINQ merece atención aparte porque no tiene equivalente exacto en Java. Es un lenguaje de consulta escrito dentro del propio lenguaje de programación, con lo que el compilador lo revisa como revisa cualquier otra instrucción. Y lo que consulta no tiene por qué ser una base de datos: la misma consulta sirve para una colección en memoria, para una base de datos relacional o para un documento XML, porque lo que cambia por debajo es el proveedor.
// la misma consulta valdría sobre una lista en memoria o sobre la base de datos
var flojos = from i in contexto.Intentos
where i.PorcentajeAciertos < 50
orderby i.Fecha descending
select new { i.SlugSubtema, i.PorcentajeAciertos };
foreach (var intento in flojos)
Console.WriteLine($"{intento.SlugSubtema}: {intento.PorcentajeAciertos}%");Que la consulta esté dentro del lenguaje tiene una consecuencia que se pregunta: los errores de una consulta LINQ los detecta el compilador, mientras que un error en una cadena de SQL no aparece hasta que la sentencia se lanza contra la base de datos.
Para el examen
ADO.NET: el equivalente de JDBC
Entity Framework: el equivalente de JPA con Hibernate
LINQ: lenguaje de consulta integrado en el propio lenguaje
Su ventaja: los errores los caza el compilador
Aplicaciones y servicios web: ASP.NET, IIS y Kestrel
El motor de ejecución no sabe nada de páginas web: no entiende de peticiones ni de respuestas HTTP. Esa capa la aporta ASP.NET, y en su versión moderna, ASP.NET Core, reúne en un único marco de trabajo lo que antes eran dos: el desarrollo de páginas con modelo, vista y controlador, y el desarrollo de servicios REST.
- ASP.NET MVC: modelo, vista y controlador. El flujo entra siempre por un controlador, que coordina la lógica del modelo y elige la vista que se devuelve. Cada controlador tiene una ruta asociada, igual que un servlet tiene su URL, y esas rutas se configuran en un punto único de la aplicación.
- Razor: la tecnología con la que se escriben las vistas, mezclando marcado y código como si fueran plantillas.
- ASP.NET Web API: la parte orientada a servicios REST, con peticiones y respuestas en JSON.
- Servicios SOAP: el estilo clásico, basado en XML y descrito por un estándar del W3C. En la plataforma sus puntos de acceso se publicaban con la extensión .asmx, y para escenarios avanzados, como la seguridad a nivel de mensaje, se recurría a WCF.
Conviene fijar la correspondencia correcta con el mundo Java, porque es donde más se falla: los servicios SOAP se corresponden con JAX-WS, y los servicios REST de ASP.NET Web API se corresponden con JAX-RS. ASP.NET MVC, en cambio, no es el equivalente de JAX-RS: es un marco de páginas, más cercano a Jakarta Faces o a Jakarta MVC.
Falta el servidor. En Windows, el servidor de referencia es IIS (Internet Information Services), que hace tres papeles a la vez: sirve contenido estático como cualquier servidor web, ejecuta aplicaciones .NET y puede actuar también como servidor de transferencia de ficheros. Su configuración por aplicación vive en un fichero propio, el web.config. En el .NET moderno y multiplataforma el papel de servidor lo hace Kestrel, que va incorporado en ASP.NET Core y funciona igual en Windows y en Linux, normalmente con otro servidor delante haciendo de intermediario.
La correspondencia limpia es: JAX-WS con los servicios SOAP, JAX-RS con ASP.NET Web API, y el servidor de aplicaciones Jakarta EE con la pareja IIS más el motor de ASP.NET, o con Kestrel en el .NET moderno.
Para el examen
ASP.NET Core: reúne MVC y Web API
Vistas de MVC: Razor
Correspondencias: SOAP con JAX-WS, y ASP.NET Web API con JAX-RS
Servidores: IIS con su web.config, o Kestrel en el .NET moderno