En el fascinante mundo de C Sharp, no solo las clases juegan un papel central en la programación orientada a objetos. Existen otros tipos, como las estructuras y los registros, que, aunque menos conocidos, son igualmente relevantes para escenarios específicos. Aprovechar estas diferencias puede optimizar tu código y facilitar la resolución de diversos problemas en C Sharp.
¿Cuál es la diferencia entre clase, estructura y registro?
A lo largo del curso, hemos explorado las clases en profundidad. Aquí, las diferencias entre clase, estructura y registro se vuelven vitales:
Clases: Operan a través de referencias. Al crear un objeto, se reserva una posición de memoria y cada instancia será única, incluso si los datos son idénticos.
Estructuras y registros: Funcionan basados en valores. Dos objetos con los mismos datos se consideran iguales.
Las clases son increíblemente versátiles y adecuadas para cualquier nivel de complejidad, desde componentes pequeños hasta soluciones grandes y complejas. En contraste, las estructuras y los registros son ideales para objetos pequeños y centrados en valores.
¿Cuándo utilizar estructuras o registros?
Las estructuras y los registros resultan útiles para:
Comparar objetos por valor: Ideal para objetos muy pequeños con pocas propiedades.
Datos inmutables: Especialmente relevante para los registros, donde los datos no cambian con el tiempo.
Por ejemplo, si necesitas comparar propiedades de objetos sin evaluar cada uno manualmente, los registros proporcionan una solución eficiente.
Ejemplo práctico: comparando clases y registros
Comparativa con clases
En el siguiente ejemplo, creamos dos objetos superman y superman2 basados en la clase superhéroe. Ambos poseen los mismos datos, pero al compararlos, el resultado es false debido a que son instancias separadas con diferentes referencias de memoria:
var superman =new Superhéroe { Id =1, Nombre ="Superman", IdentidadSecreta ="Clark Kent"};var superman2 =new Superhéroe { Id =1, Nombre ="Superman", IdentidadSecreta ="Clark Kent"};Console.WriteLine(superman == superman2);// Output: false
Cómo funcionan los registros
Al utilizar registros, la misma comparación evaluaríamos como true, ya que C Sharp permite comparar los conjuntos de valores internos de forma directa:
Como ves, mientras que en las clases el resultado es false, con registros es true.
¿Por qué usar registros en microservicios?
Imagina que trabajas con microservicios, donde los registros de múltiples mensajes deben ser comparados. Aquí, los registros son una elección perfecta, ya que simplifican la comparación y permiten un enfoque más directo y eficiente, sin necesidad de verificación propiedad a propiedad.
Ejercicio recomendado
Para poner en práctica lo aprendido, te invitamos a:
Completar el tipo record agregando más propiedades y comparar valores.
Crear un tipo structure y realizar un ejercicio similar.
Pronto: Modificadores de acceso en C Sharp
El conocimiento sigue creciendo. En la próxima lección, exploraremos modificadores de acceso en C Sharp, enriqueciendo aún más tus habilidades y comprensión del lenguaje. ¡Nos vemos allí!
RECORD
En C#, un "record" es un tipo de referencia inmutable introducido en C# 9.0 que se utiliza para modelar datos simples y valores inmutables. Los "records" son especialmente útiles cuando tienes un conjunto de datos que no cambia después de su creación y deseas garantizar que no se pueda modificar. Algunas de las ventajas y casos de uso comunes de los "records" incluyen:
Inmutabilidad: Los "records" son inmutables de forma predeterminada, lo que significa que sus valores no pueden cambiar después de que se hayan creado. Esto garantiza que los datos permanezcan consistentes y predecibles.
Facilidad de Igualdad: Los "records" facilitan la comparación de igualdad de objetos basándose en sus valores en lugar de sus referencias. Esto es útil al realizar comparaciones de igualdad en lugar de referencia.
Sintaxis Concisa: Los "records" tienen una sintaxis concisa para definir propiedades y métodos. Puedes definir propiedades de solo lectura de manera abreviada.
Desestructuración: Los "records" admiten la desestructuración, lo que significa que puedes descomponer un objeto "record" en sus componentes individuales.
Patrones de Coincidencia: Los "records" funcionan bien con patrones de coincidencia, lo que facilita la escritura de código que responde a diferentes combinaciones de valores de objetos "record".
Usos Comunes: Los "records" son ideales para modelar tipos de datos simples como puntos, vectores, coordenadas geográficas, datos de sensores y otros valores inmutables.
Aporte
Los records son especialmente útiles cuando necesitas representar datos que no cambian después de su creación, como datos de entidades. Algunas de las características clave de los records incluyen la inmutabilidad, la facilidad de comparación y la concisión en la sintaxis de definición.
Las principales diferencias entre una Record y una clase en C# son:
Comparación: Las Records comparan sus valores de manera estructural, mientras que las clases se comparan por referencia. Dos instancias de una clase con los mismos valores no son iguales, pero dos Records con los mismos valores sí.
Inmutabilidad: Las Records son inmutables por defecto, es decir, una vez creadas, sus propiedades no pueden cambiar. Las clases, en cambio, permiten la modificación de sus propiedades.
Sintaxis y Simplicidad: Definir una Record es más conciso que una clase, ya que no necesitas definir métodos adicionales si no son necesarios.
Estos aspectos hacen que las Records sean ideales para estructuras de datos que requieren igualdad de valor, como en microservicios.
Al intentar hacer el ejercicio con structs, me generaba un error al compilar, resulta que en C#, los structs pueden compararse utilizando el operador ==, pero solo si han sobrecargado explícitamente este operador o si sus campos son tipos que implementan comparaciones por defecto (como tipos primitivos).
Por defecto, los structs no tienen el operador == definido, por lo que si intentas compararlos directamente sin sobrecargar este operador, obtendrás un error de compilación. Sin embargo, todos los structs heredan de System.ValueType, lo que significa que puedes usar el método Equals para hacer una comparación de igualdad de sus campos.
Los structs son tipos de valor, por lo que no pueden compararse por referencia. No existe una implementación por defecto de == para structs porque la comparación por miembros no siempre es una comparación válida, dependiendo del tipo.
Despues de tantos años, veo una manera ejemplar de como poder hacer notar las diferencias sin palabras domingueras ni explicaciones rebuscadas, super entendido, agradezco al excelente maestro! KUDOS!!
Gran clase!!!
CLASE: la forma en la que se crean o se comparan los elementos dentro del código es a través de referencias. Eso significa que cada vez que creamos un objeto con esa clase, se va a apartar una posición de memoria para almacenar los datos de ese objeto y se le va a asignar un identificador a esa posición de memoria. Si creamos otro objeto con exactamente los mismos valores de todas maneras va a ser un objeto diferente ya que cada uno de los objetos va a tener una referencia diferente.
Comparto mi código como quedo ```c#
// Proyecto de One Piece para diferenciar las frutas que tienen los personajes, debilidades, fuerza y niveles de despertar
// Se crea una instacia de la clase PoderesPirataOnePiece representando a Luffy
using System.Text;
var NikaPoderes = new PoderesPiratasOnePiece();
NikaPoderes.Nombre = "Gear Fifth"; // Nombre del poder de Luffy.
NikaPoderes.Descripcion = "Luffy alcanza un nuevo nivel de poder con su Gear Fifth, que le permite manipular su cuerpo como si fuera de goma y aumentar su fuerza y velocidad a niveles increíbles.";// Descripción del poder de Luffy.
NikaPoderes.Nivel = NivelPiratasOnePiece.MuyAlta; // Luffy tiene una recompensa muy alta debido a su poder y hazañas.
// Se crea una segunda instancia de la clase PoderesPirataOnePiece representando a Luffy
var NikaHaki = new PoderesPiratasOnePiece();
NikaHaki.Nombre = "Haki del Rey"; // Nombre del poder de Luffy.
NikaHaki.Descripcion = "Luffy ha desarrollado un Haki del Rey extremadamente poderoso, que le permite dominar a sus oponentes y aumentar su presencia en el campo de batalla.";// Descripción del poder de Luffy.
NikaHaki.Nivel = NivelPiratasOnePiece.MuyAlta; // Luffy tiene una recompensa muy alta debido a su poder y hazañas.
// Se crea una instacia de la clase PoderesPirataOnePiece representando a Zoro
var RoronoaPoderes = new PoderesPiratasOnePiece();
RoronoaPoderes.Nombre = "Santoryu"; // Nombre del poder de Zoro.
RoronoaPoderes.Descripcion = "Zoro utiliza su técnica de Santoryu, que le permite manejar tres espadas a la vez, aumentando su poder de ataque y defensa.";// Descripción del poder de Zoro.
RoronoaPoderes.Nivel = NivelPiratasOnePiece.Alta; // Zoro tiene una recompensa alta debido a su habilidad y logros.
// Se crea una segunda instancia de la clase PoderesPirataOnePiece representando a Zoro
var RoronoaHaki = new PoderesPiratasOnePiece();
RoronoaHaki.Nombre = "Haki de Observación"; // Nombre del poder de Zoro.
RoronoaHaki.Descripcion = "Zoro ha perfeccionado su Haki de Observación, lo que le permite anticipar los movimientos de sus oponentes y reaccionar con rapidez.";// Descripción del poder de Zoro.
RoronoaHaki.Nivel = NivelPiratasOnePiece.Alta; // Zoro tiene una recompensa alta debido a su habilidad y logros.
// Se crea una instancia de la clase PirataOnePiece representando a Luffy
var luffy = new PiratasOnePiece();
luffy.Id = 1;
luffy.Nombre = "Monkey D. Luffy";
luffy.FrutaDelDiablo = "Gomu Gomu no mi";
luffy.Tripulación = "Sombrero de Paja";
luffy.PuedeNadar = false;
//Utilizo las clases de PoderesPirata de la linea 68 del codigo
List<PoderesPiratasOnePiece> poderesLuffy = new List<PoderesPiratasOnePiece>();
poderesLuffy.Add(NikaPoderes); // Agrega el poder Gear Fifth a la lista de poderes de Luffy.
poderesLuffy.Add(NikaHaki); // Agrega el poder Haki del Rey a la lista de poderes de Luffy.
luffy.Poderes = poderesLuffy;
//string resultUsarPoderes = luffy.UsarPoderes(); // Llama al método UsarPoderes() de Luffy, que recorre y muestra todos los poderes que posee.
//Console.WriteLine(resultUsarPoderes); // Muestra por consola los poderes que está usando Luffy.
luffy.UsarPoderes(); // Llama al método UsarPoderes() de Luffy, que recorre y muestra todos los poderes que posee.
// Se crea una instancia de la clase PirataOnePiece representando a Zoro
var zoro = new PiratasOnePiece();
zoro.Id = 2;
zoro.Nombre = "Zoro";
zoro.FrutaDelDiablo = "Ninguna";
zoro.Tripulación = "Sombrero de Paja";
zoro.PuedeNadar = true;
var zoro2 = new PiratasOnePiece();
zoro.Id = 2;
zoro.Nombre = "Zoro";
zoro.FrutaDelDiablo = "Ninguna";
zoro.Tripulación = "Sombrero de Paja";
zoro.PuedeNadar = true;
Console.WriteLine(zoro == zoro2); // Compara si las dos instancias de Zoro son iguales, lo que debería ser cierto ya que tienen los mismos valores.
PiratasOnePieceRecord piratasOnePieceRecord = new PiratasOnePieceRecord(1, "Zoro", "Ninguna"); // Crea un record de Zoro con los valores especificados.
PiratasOnePieceRecord piratasOnePieceRecord2 = new PiratasOnePieceRecord(1, "Zoro", "Ninguna"); // Crea un record de Zoro con los valores especificados.
Console.WriteLine(piratasOnePieceRecord == piratasOnePieceRecord2); // Compara si los dos records de Zoro son iguales, lo que debería ser cierto ya que tienen los mismos valores.
//Utilizo las clases de PoderesPirata de la linea 68 del codigo
//List<PoderesPiratasOnePiece> poderesZoro = new List<PoderesPiratasOnePiece>();
//poderesZoro.Add(RoronoaPoderes); // Agrega el poder Santoryu a la lista de poderes de Zoro.
//poderesZoro.Add(RoronoaHaki); // Agrega el poder Haki de Observación a la lista de poderes de Zoro.
//zoro.Poderes = poderesZoro; // Asigna la lista de poderes a Zoro.
////resultUsarPoderes = zoro.UsarPoderes(); // Llama al método UsarPoderes() de Luffy, que recorre y muestra todos los poderes que posee.
////Console.WriteLine(resultUsarPoderes); // Muestra por consola los poderes que está usando Zoro
//zoro.UsarPoderes(); // Llama al método UsarPoderes() de Zoro, que recorre y muestra todos los poderes que posee.
// Clase que representa a un pirata del universo One Piece.
class PiratasOnePiece
{
public int Id = 1; //Identificador único del pirata.
public string Nombre;// Nombre del pirata.
public string FrutaDelDiablo; // Nombre de la fruta del diablo que posee el pirata(si tiene).
public string Tripulación; // Nombre de la tripulación a la que pertenece el pirata.
public List<PoderesPiratasOnePiece> Poderes = new List<PoderesPiratasOnePiece>(); //Niveles de despertar alcanzados por el pirata (puede ser una lista de habilidades o etapas).
public bool PuedeNadar; //Indica si el pirata puede nadar (los usuarios de frutas del diablo no pueden nadar).
//Creación de constructor para la Clase PiratasOnePicepublicPiratasOnePiece(){Id=1;// Inicializa el identificador del pirata con el valor 1 por defecto.Poderes=newList<PoderesPiratasOnePiece>();// Crea una lista vacía de poderes para el pirata.PuedeNadar=false;// Por defecto, el pirata no puede nadar (útil para usuarios de frutas del diablo).}// Método que recorre y muestra todos los poderes que posee el pirata con public void UsarPoderes()publicvoidUsarPoderes(){// Recorre cada poder en la lista de poderes del pirata.foreach(var item inPoderes){// Muestra por consola el nombre del pirata y el poder que está usando.Console.WriteLine($"{Nombre} Esta usando el poder {item.Nombre}!!");}}//Metodo que recorre y muestra todos los poderes que posee el pirata con public string UsarPoderes()//public string UsarPoderes()//{// StringBuilder stringBuilder = new StringBuilder(); // Crea un StringBuilder para construir la cadena de salida.// // Recorre cada poder en la lista de poderes del pirata.// foreach (var item in Poderes)// {// // Agrega el nombre del pirata y el poder que está usando al StringBuilder.// stringBuilder.AppendLine($"{Nombre} Esta usando el poder {item.Nombre}!!");// }// return stringBuilder.ToString(); // Devuelve la cadena construida por el StringBuilder.//}
}
//Clase que representa los poderes de un pirata del universo One Piece.
class PoderesPiratasOnePiece
{
public string Nombre; // Lista de habilidades del pirata.
public string Descripcion; // Lista de debilidades del pirata.
public NivelPiratasOnePiece Nivel; // Nivel de despertar del pirata.
// Constructor de la clase PoderesPiratasOnePiece.// Este constructor inicializa el nivel del poder como MuyAlta por defecto,// lo que indica que, si no se especifica otro valor, el poder será considerado de nivel muy alto.publicPoderesPiratasOnePiece(){Nivel=NivelPiratasOnePiece.MuyAlta;// Asigna el nivel MuyAlta como valor predeterminado al crear un nuevo poder.}
}
// Clase que representa los niveles de un pirata del universo One Piece.
enum NivelPiratasOnePiece
{
Bajo = 1000000, // Recompensa baja.
Media = 5000000, // Recompensa media.
Alta = 10000000, // Recompensa alta.
MuyAlta = 50000000 // Recompensa muy alta.
}
// Clase de record que representa los poderes de un pirata del universo One Piece.
public record PiratasOnePieceRecord( int Id,string Nombre, string FrutaDelDiablo);
//Compare Hero #4 vs. Hero #5Hero.HeroRecord batman =new(4,"Bruce Wayne","Batman", false, new List<Colors>{ blackColor, yellowColor }, true, new List<SuperPower>{ strengthPower });Hero.HeroRecord spiderman =new(5,"Tobey Maguire","Spider-man", false, new List<Colors>{ blueColor, redColor }, true, new List<SuperPower>{ strengthPower });Console.WriteLine(batman == spiderman);//Output: False
public record SuperHeroRecord(int id, string nombre, string IdentidadSecreta);