📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

CURSO DE C# .NET GRATIS (Intensivo)

hdeleon.net1:16:36

Transcription

Qué tal, mi nombre es Hector de León y soy mejor conocido como el único programador que tomar café le da resaca y una buena resaca. Este es un curso gratuito intensivo de C# orientado a las personas que quieran aprender C# rápidamente. Aquí nos metimos a enseñar conceptos, igual si tú los aprendes con C# y te vas a otro lenguaje de programación, no tendrías dificultad para volverlos a replicar.

Este curso es parte de un curso de paga llamado Programación Backend C# .NET, que puedes adquirir ahí en el primer comentario a un precio muy barato. El objetivo de este curso intensivo de C# es que tú conozcas los aspectos fundamentales del lenguaje de C# y puedas tomar cualquier otro curso, ya sea para backend, ya sea para frontend con Blazer, para videojuegos, para Internet de las Cosas, para aplicaciones de escritorio. Es decir, este curso se enfoca al lenguaje de programación principal de .NET llamado C#. Así que vas a ver programación orientada a objetos, vas a ver programación funcional, vas a ver también la extensión de C# llamada LINQ.

Y bueno, el curso es gratuito, así que ve dando pulgar arriba, suscríbete y si quieres adquirir el curso de Programación Backend C# .NET, bueno, pues ya sabes, primer comentario, la descripción, puedes adquirirlo y te agradeceré bastante. Ahora sí, vamos al curso.

¿Qué es .NET? .NET es un marco de trabajo. ¿Y qué es un marco de trabajo? Un marco de trabajo es una estructura, una organización que te va ir indicando cómo ir haciendo una aplicación, dónde poner cierta cosa, cómo nombrar esta cosa, con qué se conecta o cómo se conecta a otra cosa. Estas cosas son tus códigos y en este punto podrán ser tus clases, tus interfaces.

Bueno, .NET es un marco de trabajo que nace como .NET Framework en 2002. Esta primer versión de .NET es privada, es decir, no es código abierto. 2002, esto nace para hacer una competencia contra las aplicaciones web que estaban ya hechas en PHP y en Java por parte de Microsoft. Bueno, más adelante, en 2014, se decide crear un .NET de código abierto y multiplataforma, el cual se es llamado .NET Core, que es lanzado en 2015.

Este .NET Core llega hasta la versión 3, que a partir de la versión 3 tiene que cambiar su nombre. ¿Por qué? .NET Framework, que era el privado, esta a la par con .NET Core. .NET Framework llegó hasta la versión 4.8. .NET Core iba en la versión 3. Iba a haber cierta confusión llamar .NET Core 4 cuando existía .NET Framework 4 y eran dos tecnologías distintas, una era privada y la otra era open source y multiplataforma. Entonces, Microsoft decide llamar y brincarse el 4 en .NET Core y llamar simplemente a .NET Core ahora .NET 5. Así tal cual, sin framework, sin Core.

.NET 5 es código abierto, multiplataforma y a partir de ahí empieza a cambiar de nombre a .NET 6, .NET 7 y en este curso nos enfocamos más a .NET 8. Aunque no hay tantas diferencias en cuanto a lo que vamos a ver aquí, si estás trabajando con .NET 5, .NET 6, no hay tantas diferencias, así que no te preocupes por ello. Y cuando hay una diferencia, te lo voy a indicar. Esto es parte .NET 8.

En este curso nos vamos a enfocar a trabajar con .NET y C#. Y si no sabes la diferencia de qué es C# y .NET, C# es el lenguaje de programación, .NET es el framework. Y con .NET 8 puedes hacer aplicaciones de videojuegos, puedes hacer aplicaciones web, puedes hacer aplicaciones de Internet de las Cosas, aplicaciones de escritorio, puedes hacer muchísimas más cosas. Así que .NET es una tecnología con la cual si la aprendes, puedes cambiar a otras áreas sin tanta complejidad. Así que adelante, vamos a continuar con este curso.

En esta sección vamos a ver una un curso intensivo de C#. Esto sí, esto es hecho para personas que vengan de otro lenguaje de programación, ya tengan nociones y quieran ver ciertas cositas. Vamos a ver ciertas cositas que van a ser necesarias para el curso de backend, que en C# podrían confundir los si vienen de Python, vienen de JavaScript, vienen de otro lenguaje de programación. Este curso es para eso, para que se familiaricen con el lenguaje.

Voy a abrir Visual Studio 2022. Vamos a darle aquí, crear un proyecto. Vamos a crear un proyecto de consola. Todo este proyecto es independiente a todo el curso de backend. Este es un curso intensivo, por lo cual si tú ya sabes C#, lo puedes saltar. Aquí vamos a dar en "Aplicación de consola", darle siguiente y vamos a ponerle un nombre a este curso, a este a este proyecto. Yo le he puesto "Intro C# Backend". Le vamos a dar siguiente y aquí regularmente deberías tener .NET 8. Igual, si tienes .NET 7, 6, 5, no va a haber mucho problema, no vamos a ver nada que tenga que involucrar nuevas cosas. Vamos a darle en "Crear".

Aquí en Visual Visual Studio 2022 se nos ha creado el proyecto de consola, el cual solamente tiene un archivo llamado Program. Si yo ejecuto esto en este botón que está aquí, que tiene un símbolo, un icono de Play, le ejecutamos. Esto va a ser la ejecución, pero también la compilación. C# es un lenguaje de programación el cual es compilado, por lo cual necesita compilar y después ejecutarse. Aquí vemos el mensaje de "Hello World".

Bien, en esta clase lo que vamos a ver es cómo se crean eh clases y objetos. Una clase es un molde para creación para la creación de un objeto. Un objeto es una entidad la cual puede tener eh puede tener información y puede tener un comportamiento. Los objetos los vemos en todo el universo, o sea, los podemos ver en tú como persona, en tú como tu cerveza, en tus mascotas, en tu auto. Todos son objetos que tienen propiedades. Un auto tiene puertas, color, llantas, número de llantas, tamaño de llanta y tiene también comportamiento: sirve para eh acelera, frena, da vuelta, etcétera. Eso es lo mismo en la programación.

Para yo crear un molde, una clase, basta con que ponga aquí `class` y ponemos el nombre de mi clase, en este caso `Sale`, y le damos llaves de apertura. Y para poner yo una propiedad, voy a poner `public` para que sea pública, para poder acceder desde donde yo esté, de donde yo quiera. Vamos a poner que esto sea público, vamos a poner que sea un tipo `decimal` y que sea el nombre `Total`, para que yo le permita a esta propiedad que puedas acceder a ella y a modificarla. Le puedo agregar el `get` y el `set`. Yo si quisiera que esta propiedad solamente pudieras acceder a ella, quito el `set`. Si yo quisiera que solamente pudieras modificarla, quito el `get`. Entonces, de esa manera nosotros podemos encapsular el comportamiento. De esta manera, solamente podría modificarla. De esta manera, solamente podría obtenerla.

Bien, pero lo ideal es que tú tengas esto muy en claro, que si esta propiedad va a ser accedida desde cualquier parte, puedes hacerla pública. También, aunque en realidad en C# no te van a permitir solamente tener `set`. Si tú dejas el `set`, no te va a permitir. Debes tener por lo menos un `get`, pero sí puedes tener un `get` solo, es decir, el `get` sí se puede estar solito para que tú solamente le accedas, pero no la no la modifiques.

Bien, teniendo esto, yo para crear un objeto puedo hacerlo de tres formas. Una es escribiendo la palabra `Sale` seguido del nombre de mi objeto, igual a `new Sale()`. Esta es la primera forma y esto ya funcionaría. Yo ya podría ponerle a `Sale` el `Total`, por ejemplo. Aquí vamos a poner esto se le podría poner `Total` y le podría poner un valor, no, en este caso un 15. Si yo aquí quitara este `set` que está aquí, esto no me permitiría, me marcaría error, ya que no esté dando acceso a la propiedad para poder ser modificada.

Bien, una vez teniendo esta forma, la segunda forma es que en C# tú puedes definir el objeto con lo que está a la derecha. Por lo cual, hacer esto, estar escribiendo `Sale` una vez y `Sale` otra vez, te lo puedes ahorrar escribiendo `var`. Simplemente acá. Este es un problema común que personas que vienen de JavaScript piensan que este `var` es igual que el de JavaScript. No, no tiene nada que ver con el de JavaScript. Esto simplemente es azúcar sintáctica para ahorrarte escribir acá el nombre de la clase dos veces. Y qué pasa en JavaScript, podría ser cosas como esta, no, de repente convertirlo a lo que tú quieras. Bueno, aquí no se puede. Una vez que se entiende esto, esto es algo primordial, es pregunta de técnica de la diferencia del `var` de C# al al de JavaScript, porque es muy común que las personas se confundan. No tiene nada que ver uno con el otro.

Bien, si te preguntas qué es azúcar sintáctica, azúcar sintáctica es una cualidad que tiene los lenguajes de programación que van adquiriendo nuevas formas de escribir las cosas de manera más rápida, de manera más pequeña, de manera más legible.

La tercera forma para escribir un objeto, para crear un objeto, es la siguiente. Nosotros podemos crear un objeto si simplemente aquí escribiendo la palabra `Sale` y aquí quitando este `Sale` y dejando `new`. De esta manera, nosotros también podemos crear un objeto. Esta es una de las nuevas formas que fue añadida los últimos años, no es tan utilizada, pero está una forma que también se puede utilizar.

Bien, nosotros podemos darle a un objeto un elemento desde su creación. Esto se llama un constructor. Un constructor tiene el mismo nombre que la clase a la que está hecha. El constructor puede, puedes obligar que desde el momento de la creación reciba algo. En este caso, puedo obligar que reciba el `Total` del momento de la creación. Vamos a dar aquí con `this.Total = Total;`. Este `this` hace referencia a los elementos de la clase. Yo igual, esto lo puedo evitar porque este `Total` se llama diferente al `Total` que estoy recibiendo. El `Total` que estoy recibiendo está en minúscula y el `Total` que tengo aquí es un `Total` que tiene una mayúscula, por lo cual son diferentes. Pero si yo tuviera este `Total` en minúscula aquí, C# no sabría cuál `Total` me refiero, por lo cual aquí al poner `this.Total`, ya sabría que me refiero al que tiene la clase, al que tiene el objeto. Cuando hablamos de clases, es la estructura, el molde. Cuando hablamos de objetos, es el que ya está haciendo en ejecución.

Bien, aquí ya teniendo esto, vamos a regresarlo con la T grande porque las propiedades, por una cosa llamada convención, se escriben con mayúscula al inicio. Esa convención es algo, son reglas políticas que tienen los lenguajes de programación, son sugerencias con las cuales tú es como te tienes que nombrar las cosas. De esta manera, tú vas a ver código con más formalidad o uniformidad cuando estás viendo ejemplos en una documentación, cuando estás viendo otro proyecto. Si siguen estas convenciones que sugieren el mismo la documentación de C#, pues el código se te va a ser más familiar.

Bien, aquí lo que yo ya si vemos podemos detectar es que la clase en la creación me está diciendo que esto está, voy a ponerle aquí que esto está erróneo, ya que me está exigiendo en su construcción, me está exigiendo un valor. Entonces, aquí vamos a ponerle un 15 y ya está. De esa manera, ya se ha quitado el error.

Las clases también pueden especificar comportamiento. Por ejemplo, en este caso, yo voy a poner `public void`, vamos a poner `public void`, vamos a poner el `string`, eh, `getTotal` o `getInfo`. Vamos a poner `getInfo` y este `getInfo` lo que va a retornar es un mensaje que tenga la información. "El total es " y nosotros para concatenar con C# podemos utilizar el el símbolo de más, el símbolo de plus, y aquí vamos a ponerle `Total`. Y punto y coma y listo. Ya tenemos nuestro método, nuestro comportamiento de nuestra clase. Y ese comportamiento de la clase lo van a tener los objetos que se crean con ese molde, con ese molde para hacer pasteles. Creamos este pastel llamado `Sale` y ese pastel tiene un comportamiento llamado `getInfo`, el cual retorna un `string`. Ese `string` yo lo puedo recibir aquí. También puedo especificarlo con `var` porque lo de la derecha me va a decir que es un `string` ya automáticamente. `message`, vamos a poner `sale.getInfo()`. Y de esta manera podemos también especificar la creación de un elemento, una variable, en este caso una variable del tipo `string`, ya que `getInfo` está diciendo que es `string`. Si yo pongo aquí el cursor, me dice que es un `string`.

Bien, y yo para imprimir esto en pantalla, voy a ponerlo con `Console.WriteLine(message);` y de esta manera ya tenemos el comportamiento. Aquí ejecutándola, vemos el comportamiento ejecutado del objeto. Y tú, de esta manera, puedes crear otros tipo, otros objetos ahí. Vemos "El total es 15". Puedes crear otros objetos del tipo `Sales`, ya que tienes tu molde para hacer esos objetos. Esos es clases y esos son objetos, prácticamente.

A lo mejor lo que te confundas, este `public`, `public`, `public`, eso es solamente un accessor. Es un sirve para tú decirle, okay, este esta propiedad es pública, quiero que acceda en cualquier parte, pero también podrás crear propiedades que son privadas, las cuales solamente pueden accederse de manera local. Por ejemplo, `som`. Aquí vamos a poner `som`. Este `som` yo no puedo acceder acá fuera. Por ejemplo, yo sé, no puedo, no puedo ir a `Z`, no, no lo puedo acceder, va a marcar error, pero sí puedo acceder aquí, por ejemplo. Entonces, aquí puedo acceder. Vamos a ponerle un ocho, lo que sea. Ese `Z`, si puedo acceder lo internamente. La convención en C# para cosas privadas es poner un guion bajo al inicio. De esta manera, tú si estás viendo una clase que está muy larga y ves abajo algo que tiene un guion bajo, dices, ah, okay, este es un es algo que es privado.

También hay otra cualidad que pueden tener las cl eh las clases en cuanto a acceso de de el comportamiento, acceso de información, es que puede ser protegida y el protegido vamos a verlo más adelante, que tiene que ver con cuando estás utilizando herencia. El protegido puede acceder solamente la misma clase o sus hijos que hereden de ella. Pero en este caso, vamos a dejarlo esto en privado. Y de esta manera, ya sabemos que el privado solamente puede acceder esta clase, nadie más, ni una ni una clase que herede de ella, nadie más.

Estos accessors también pueden ser utilizados en los métodos. Por lo cual, si yo aquí hago un método que sea privado, me debería marcar un error aquí afuera. Te fijas, aquí me marca un error en `getInfo`, ya que no es privado, ya que es privado, por lo cual no puede acceder. Ya lo he cambiado a público y ahora sí puedo acceder. Y bien, eso es prácticamente clases y objetos.

En esta clase vamos a ver el concepto de herencia. Herencia es parte de la programación orientada objetos. La herencia es prácticamente que tú puedas reutilizar el código existente en otra clase. Por ejemplo, ejemplo, ya tenemos una clase aquí llamada `Sale`. Nosotros podemos crear otra clase aquí. Voy a ponerla arriba que se llame `SaleWithTax`. Bien, con impuestos. Y yo puedo para decirle que quiero utilizar todo lo que tiene `Sale`, vamos a ponerle dos puntos `Sale`. De esa manera, nosotros como vamos a heredar, te fijas que me marca un error. Esto me marca porque el constructor de `Sale` me obliga a que des su creación tenga un elemento. Por lo cual, yo tengo que crear un constructor aquí, el cual indique esa esa parte, le indique y se la pueda mandar. Es decir, en la creación de este este objeto que va a ser `SaleWithTax`, vamos a especificar también que recibamos el `Total` y ese `Total` nosotros para mandárselo al padre que estamos heredando, vamos a mandarlo con dos puntos. Aquí vamos a poner `base(Total)`. Así tal cual me lo está sugiriendo. Y de esa manera se ha quitado el error.

Yo ya puedo crear objetos del `SaleWithTax` directamente utilizando ya también todo el funcionamiento. Si vamos al objeto que tenemos arriba, vamos a poner `SaleWithTax` y vamos a ver que también ha heredado el comportamiento, es decir, el `getInfo` lo ha heredado, ya que es público. ¿Qué pasa si este método `public` que está aquí lo hago privado? Lo que va a pasar es que ya no puedo utilizar `getInfo` porque este método solamente puede ser utilizado dentro de la misma clase. Es decir, yo aquí sí podría utilizarlo, por ejemplo, `getInfo()`. Aquí sí puedo utilizarlo sin problema alguno, pero `getInfo` no lo podría utilizar en la clase que estaré dando el padre. Al momento que yo esto haga de manera pública, sí podría utilizarlo.

Ahora, hay otra otro modificador de acceso llamado `protected`, que lo que hace `protected` es que los elementos tanto de la misma clase como sus hijos puedan acceder a él, pero lo que esté fuera de ello no pueda. Por eso aquí me marca un error, pero aquí no me marca un error. El hijo puede acceder, pero fuera de ello no puede acceder. En el caso que yo quiera que esto pueda acceder por todos lados, vamos a ponerlo `public` y de esta manera se resuelve.

Bien, el objetivo de la herencia es que podamos reutilizar funcionamiento. En este caso, yo ya puedo reutilizar todo lo que tengamos, por ejemplo, en `getInfo`, puedo utilizarlo, puedo utilizar las propiedades que son públicas o protegidas. Las privadas no. Y aquí yo puedo agregarle más, más cosas, más elementos. Puedo agregar, por ejemplo, `public`, vamos a poner un `decimal`, `Tax`, un impuesto, y vamos a poner que sea `get` y `set`. Listo. Yo ya tengo un elemento extra en este método. Yo también puedo ponerle comportamiento extra. Por ejemplo, puedo poner otro otro `getInfo` aquí, `GetInfoWithTax()`, y yo puedo tener los dos métodos. Puedo tener tanto el `getInfo` que ya teníamos acá y el `GetInfoWithTax()`. Aquí vamos a poner este `Total`, vamos a ponerle concatenar que el impuesto es y vamos a ponerle aquí `Tax`. Bien, y te fijas, tengo aquí nada más puse `Tax`. Así está. Tenemos aquí un un método el cual existe en el padre, podemos utilizarlo en los objetos que son del hijo. Y también tenemos un método extra y también una propiedad extra que pueden ser utilizadas en los elementos hijos.

Hay un concepto dentro de la herencia llamada sobreescritura. La sobreescritura es cuando yo tengo un método en el padre y quiero que exista el mismo método pero modificado en el hijo. Es decir, okay, el padre tiene un método, pero yo quiero modificarlo en el hijo. Para eso vamos a poner el mismo nombre `getInfo`, tal cual el del padre, y vamos a ponerle aquí `public virtual` para que esto le diga, le indique que este método puede ser sobreescrito. Y acá en el hijo, vamos a poner `override` y de esta manera, cuando yo ejecute aquí `getInfo`, que es un objeto del tipo `SaleWithTax`, el método que se va a invocar es este y no se va a invocar el del padre. Esa es una de las alternativas que tenemos cuando queremos sobreescribir el comportamiento que tiene ya el padre, decir, okay, quiero reutilizar el código de todo lo que ya tienes, pero este método quiero sobreescribirlo, quiero hacerlo a mi manera. Yo ejecutando esto, vamos a cerciorarnos que el `getInfo` que se va a ejecutar es el que se llama impuesto. Ahí está, tiene un cero porque no manda un valor para `Tax`. Nuestro constructor no necesariamente tiene que tener nuestro constructor en el hijo no necesariamente tiene que tener los mismos elementos del padre. Aquí podríamos tener los nuevos elementos también, por ejemplo, `decimal taxs`. Y aquí asignárseles. Bueno, en este caso no, no importa el `this` porque se llaman diferente. Y así de esta manera nosotros asignamos eso. Y aquí me está marcando un error porque no he mandado el impuesto. Vamos a ponerle 1.16 y en los decimales tenemos que poner una M al final para decir, indicar que es un decimal. La M es al final.

Bien, yo ejecutando esto, vamos a ver que ahora sí el impuesto se, el método, el método se va a ejecutar el del hijo y el impuesto ya va a tener un valor. De esta manera es como trabaja la herencia. Reutilizamos información, reutilizamos comportamiento e información que tienen clases ya existentes y le asignamos nuevo funcionamiento si es necesario. Esto es útil que lo entiendan, ya que cuando estamos trabajando con frameworks, no no necesariamente con ASP, sino también Laravel, otros frameworks de backend, es común que utilices la herencia en los elementos ya existentes. Cuando estás trabajando con una arquitectura MVC, porque vas a tener que heredar de lo que ya existe como modelo, de una clase llamada modelo que está hecha en el mismo framework, una clase que está hecha llamada controller, por ejemplo. Y de esa manera, tú vas a poder utilizar todo eso y también vas a tener que regularmente vas a tener que sobreescribir también métodos. Entonces, por eso era necesario que entiendan esto, la herencia y sobre todo la sobreescritura.

Hay otro tema que se llama la sobrecarga, pero la sobrecarga no lo veía tan importante en este punto porque la sobrecarga es prácticamente que tengas un método en la misma clase que tenga una entrada distinta de datos. Por ejemplo, tengo ya un `getInfo`, pero este `getInfo`, si quiero que tenga otra entrada distinta, vamos a ponerle un dato, un `message`, y de esta manera nosotros estamos haciendo una sobrecarga del método ya existente. Vamos a ponerle aquí `return message;` no más para que no me marque error. Y vemos que puedo tener métodos con el mismo nombre, mismo nombre, pero que reciban distintas entradas de datos. Eso se llama sobrecarga, que también lo vamos a ver en algunos métodos ya existentes en .NET, los cuales vas a poder ver que algunos te van a permitir mandar 1, 2, 3, 4 parámetros, pero se llama igual, eso es sobrecarga. Y nosotros pues podemos hacer sobrecarga de métodos simplemente llamándolos igual, pero con una entrada distinta de datos. Este no recibe nada, este sí recibe algo. Y yo podría crear otro `getInfo`, por ejemplo, que reciba, que reciba dos, dos, dos strings, o que reciba un `int`, `inda`, y de esta manera, pues ya es otro `getInfo`. Aquí puedo ponerle también uno que se simplemente reciba un elemento, pero está entero, por ejemplo, `inda`, y aquí vamos a ponerle a. Y te fijas, los métodos, bueno, tengo que convertirlo a `string` ahí está, porque es un `int`, pero te fijas que el punto, no es que se llamen que tengan más números de parámetros, distinto número de parámetros, sino que sean de distintos tipos las entradas. Este es un `string`, este es un entero, este no recibe nada. Se llaman igual, sí, y esto compila. Yo lo ejecuto y compila. Ahí vemos el comportamiento sin afectación alguna.

En resumen, la herencia es una forma para que podamos reutilizar el comportamiento ya existente. Ese comportamiento ya existente nos puede ahorrar mucho tiempo. La herencia permite que tú puedas utilizar las cosas que sean públicas y protegidas. Cuando son privadas, solamente las puede utilizar el padre. En este caso, hemos utilizado puro público y podemos hacer nosotros nuestros propios métodos y podremos sobreescribir el método del padre también utilizando sobreescritura con la palabra `override` y acá en el padre tenemos que especificar `virtual`. Y podemos utilizar sobrecarga haciendo métodos que que se llamen igual a lo ya existente en mi misma clase, pero con distinta entrada de datos.

Entonces, en esta clase vimos la herencia, sobrecarga y sobreescritura.

En esta clase vamos a ver lo que son las interfaces. Las interfaces, cuando digo interfaces, no me refiero a pantallas, me refiero al concepto de interfaz en programación orientada objetos. La interfaz es un contrato. Primero, vamos a ahorrar todo esto, quítese por allá. La interfaz es un contrato el cual te permite tipar, categorizar clases. Cuando tú puedes hacer esto, tú puedes hacer métodos los cuales especifiquen que reciben una interfaz, no una clase. Reciben una interfaz y de esta manera tú vas a poder recibir una clase que tenga implementación de esa interfaz. La interfaz lo que hace, la interface o interfaz, lo que hace es dar reglas. Estas reglas son: tú, si quieres implementar me, tienes que hacer estos métodos y tener estas propiedades. De esa manera, cuando tú implementas esa interfaz, vas a poder categorizar tu clase.

Vamos a hacer aquí una interface. Basta con que pongamos `interface` y vamos a poner `ISale`. Y esta interface llamada `ISale` va a tener una propiedad. Todos los que tengan esta esta interface tienen que tener la propiedad `Total` y debe ser del tipo `decimal`. Si tú no tienes la propiedad `Total` del tipo `decimal`, entonces va a marcarte un error. Yo si quiero implementar la interfaz, vamos aquí poner una clase que implemente la interfaz. De esta manera, tenemos que hacer con los dos puntos, igual que la herencia, pero aquí en el caso de la interfaz, a diferencia de la herencia, es que la interfaz sí puede hacerse múltiple. La herencia solamente puedes hacerla sobre una clase. La interfaz, la implementación de interfaces, puedes serla múltiple. Yo agrego la siguiente, la siguiente, la siguiente, la siguiente, la siguiente, y se va a no va a haber problema, siempre y cuando implemente las reglas que me está diciendo esta interface. La primera regla que me está diciendo es que tenga esta propiedad.

Bien, listo, ya tenemos esa propiedad y esto debe corregir. Y aquí para que se corrija el error, falta ponerle que sea `public`. Listo. Ya teniendo de esta manera esta parte, ya cumplimos con las reglas que nos está diciendo la interfaz a cumplir. Ahora, si yo quisiera hacer otra implementación de otra interface, vamos a poner `interface` esto que se llame `ISave`. Una interfaz que diga que lo que se implemente aquí es porque vas a tener un mecanismo para guardar. Y este mecanismo va a ser un método el cual va a llamarse `Save` y este `Save` va a ser algo que es algo, no lo sé. Yo simplemente soy una cosa, un contrato que pone las reglas. Tú quieres utilizar este contrato, bueno, cumple tener un método que no regrese nada, `void` significa que no retorna nada, no recibe nada, pero haz algo. Bien, aquí para implementar eso, vamos a poner otra interface llamada `ISave`. Y para yo cumplir con eso, tengo que cumplir con este método. Vamos a crearlo aquí debajo y de esta manera tenemos este método ya cumplido. No hace, hace algo, sí, pero hace algo, pero no, no, no le importa la interface que haga, siempre y cuando que exista. Aquí vamos a poner solamente simular que hacemos un guardado. No guarda, se guardó en base de datos, no, ahí está, listo.

Bien, yo puedo tener otro otra clase aquí debajo llamada `public class Beer`. Esto vamos a solamente implementar el `Save`, no vamos a implementar nada más más que el `Save`. Y a su vez, tengo que tener solamente este método. Se me obliga a tener solamente el método `Save`. Estoy implementando solamente la interfaz `ISave`. Y aquí vamos a poner que se guarda en `Beer`. Es decir, aquí es un comportamiento distinto, nada que ver con el de acá. Aquí se va a ir a guardar un servicio, acá se guarda en la base de datos. Es decir, mientras tú cumplas con el contrato que dice, haz un método que no retorne nada y no reciba nada y se llama `Save`, la interface no le va a importar que hagas internamente, siempre y cuando estás cumpliendo lo que te está exigiendo. Y de esta manera, nosotros tenemos una clase que se llama `Beer` que tiene solamente implementación sobre `ISave`. Acá tenemos una implementación de `ISave` sobre dos interfaces y estamos cumpliendo con eso.

Esto para qué sirve. Esto sirve para las arquitecturas de software y para los patrones de diseño, para darle categorización a tus clases. Tu clase `Sale` está categorizada como `ISale` y `ISave`. Tu clase `Beer` está categorizada como `ISave`. Si yo tengo un método aquí, una función, nosotros podemos crear funciones sin necesidad de clases. Aquí en C#, vamos a dar que ponerla acá abajo, vamos a ponerla arriba, se puede poner arriba. Vamos a poner una función que se llame `SomeAction`. Esta función que se llama `SomeAction` va a recibir algo implementado con la interfaz `ISave`. ¿Qué es eso? Pues no lo sé, simplemente a mí me interesa que cumplas con la interfaz `ISave`. Y aquí vamos a ponerle que sea algo que se llame `saveable`. Y yo ya sé que porque la interfaz está obligando a que tú cumplas con las reglas que establece esta interfaz llamada `ISave`, yo sé que en `saveable` debes tener tú ese método. Por lo cual, yo sé que internamente puedo mandarlo a llamar. Sé que puedo mandarlo a llamar. Entonces, yo aquí creo un objeto, vamos a poner crear un objeto que se llame del tipo, en este caso se va a llamar `sale` y vamos a hacerlo del tipo `Sale`. No, ahí está la `Sale`. Vamos a crear otro objeto llamado `beer` y va a ser del tipo `Beer`. Que no tiene nada que ver uno con el otro. Lo único que tienen que ver es que son parte de una categorización hecha por interfaz. Por lo cual, yo puedo aquí invocar la función `SomeAction` y puedo mandarle tanto `sale`, puedo mandarle tanto `beer`. Es decir, a yo puedo mandarle tanto `saveable` como puedo mandarle como tal cual. Y esto no va a marcar error, ya que lo que está esperando `SomeAction` es una implementación de la interfaz `ISave`. Y esto sin importar que tú hagas algo que se guarda en la base de datos, que se guarda en servicio, lo que hace este método es simplemente invocarse. No tiene que enterarse de nada lo que hace `Save`. Simplemente sabe que esta interfaz tiene un método llamado `Save` y tus clases están implementando eso. Por lo cual, desde la compilación estás protegiendo que exista eso.

Para eso son las interfaces, por eso es un concepto tan importante, porque los patrones de diseño están basados en interfaces, las arquitecturas limpias están basadas en interfaces. Vemos que esto se ejecuta sin problema alguno. Por qué. Se es la base de las interfaces, de las arquitecturas limpias y de SOLID y de patrones de diseño, porque los elementos no tienen que basarse en implementaciones, sino en abstracciones. Esto es una abstracción. La interfaz por sí misma es una abstracción, porque estás abstrayendo el funcionamiento mínimo que debería tener algo que se guarda. `ISale` es una abstracción, porque estás abstrayendo los elementos que debe tener `Sale`. Tú también puedes tener elementos extras aquí, pues, o sea, puedes tener otros elementos, no sé, y y no te va a marcar errores. Es decir, tú mientras cumplas con lo que estás implementando, puedes tener cosas extras. Y lo que está dependiendo simplemente es que hagas lo que te está diciendo las interfaces. Para eso sirve. Cuando tienes un sistema grande y un día se te ocurre modificar un comportamiento, por ejemplo, ahora nos vamos a guardar en la base de datos, vamos a guardar en a lo mejor en un servicio tercero, o vamos a guardar en S3, o una base de datos de cloud, etcétera. Tú simplemente modificas esto y no tienes que ir a modificar dónde estás llamando ese objeto. El objeto, mientras cuando sigas cumpliendo con esta interfaz, no tiene que enterarse de que estás modificando, no tiene que enterarse de nada. Por eso las interfaces son importantes, porque te hacen crear código más escalable, te hacen crear código más limpio y más modificable. Vamos a abordar más este concepto dentro del curso de backend, pero esto es solamente la base para que entiendas y cuando lleguemos al backend nos digas, oye, qué es eso de interface. Bueno, ya viste una base. Vamos a ver más a fondo en en el curso de backend y ahí te va a quedar muchísimo más claro porque vamos a verlo ya con cosas reales.

En esta clase vamos a ver los generics. Los generics te sirven para hacer métodos y clases genéricas. Es un mecanismo que existe en los lenguajes de programación orientada objetos, no solo en C#, también los podemos ver en Java, también los puedes ver en TypeScript. Estos generics te van a ayudar a reutilizar código, tanto métodos como clases. Generic va a ser muy común cuando se utilicen colecciones, es decir, una colección, un tipo de data array, lista, porque de esta manera podemos reutilizar el modelo de negocio, la funcionalidad que tenemos sobre esa lista para distintos tipos de datos. Estos tipos de datos pueden ser desde un entero, un string, o objetos por sí mismo.

Entonces, aquí vamos a hacer unos ejemplos con generics para que quede más claro. Aquí vamos a comenzar haciendo una clase llamada `MyList`. Para especificar que mi lista va a tener un generic, voy a poner un menor que, mayor que, y una `T`. Tú puedes poner otras letras aquí, pero yo te recomiendo por estándar poner una `T`. Una vez que tengamos esa `T`, esta `T` va a ser nuestro tipo de dato, nuestro tipo de dato lo desconocemos, no sabemos qué sea. Aquí vamos a poner nosotros una lista. Vamos a crear una propiedad la cual va a ser privada. Vamos a ponerla del tipo `List`. `List` es un tipo de datos de de hecho que este mismo tipo de datos, te fijas, recibe un `generic` y eso se lo vamos a agregar a esta lista. También vamos a recibir otro tipo, tipo de elemento, el cual va a ser la longitud de nuestra lista. Y los dos, los dos elementos, los voy a hacer privados, por lo cual he puesto un guion bajo. Esto solamente por convención de escritura de cómo se nombran las cosas.

Vamos a crear un constructor el cual se llame `MyList` y se tiene que llamar exactamente como tu tu clase. Y aquí esta vamos a recibir la longitud que tiene que tener nuestra lista. Esta clase lo que va va a hacer es tener una lista de elementos limitada. Por eso he utilizado una lista y a su vez le estoy pasando el tipo y el tipo. Bien, una vez que tengamos esto, vamos a poner aquí el límite y lo vamos a asignar en la construcción.

Ahora, yo sí quiero crear un objeto de este tipo de de clase, vamos a poner `var numbers = new MyList<int>();`. Y vamos a ponerle el tipo entero. Te fijas cómo le estoy pasando el `int` aquí a la `T`, y esta `T` se la pasa para acá también. Y de esta manera, yo estoy definiendo un una un objeto del tipo eh de `MyList`. Aquí me falta `MyList`. Ahí está, `MyList` del tipo `MyList`. Y solamente falta poner la longitud. Por ejemplo, aquí vamos a ponerle cinco. Y estamos definiendo un tipo de objeto con mi clase y le estamos pasando el tipo con el cual va a trabajar.

Ahora, aquí lo que voy a hacer, puedo hacer, por ejemplo, también `names`, ya tengo `numbers`. Vamos a poner `names = new MyList<string>();`. Y vamos a poner que este sea del tipo `string`. O se va a ser `string` y va a tener también cinco nombres. Te fijas que puedo trabajar con distintos tipos de datos con la misma clase. Yo este objeto no puedo agregarle elementos, ya que es privada a la lista que tiene internamente. Yo voy a hacer un método para hacer ese proceso. Vamos a ponerlo aquí `public void Add(T element)`. Y este método va a recibir algo del tipo que tenemos en esa clase. Por eso vamos a ponerle la `T`. En lugar de poner aquí un `int` o poner un `string`, no vamos a limitarlo a eso, no vamos a limitarlo a eso, vamos a limitarlo a que el tipo tú lo estés mandando en la creación de tu objeto y va a trabajar con ese tipo para todo lo que tenga esa `T`.

Aquí vamos a poner el elemento, vamos a poner `element`, pero vamos a evaluar algo. Vamos a poner si tu lista, `list`, que está interna, es su longitud, hay una propiedad que se llama `count`. Si su longitud es menor a `limit`, pues va a hacer algo. Y ese algo va a ser lo siguiente: vamos a agregarlo con `list.Add(element)`. Y esto lo que nos va a ayudar a no solamente falta un guion bajo. Esto lo que nos va a ayudar es hacer listas limitadas. Es decir, tu lista va a tener un un cupo, un no vas a poder agregar seis elementos o el que número que tú pongas. Si pones 50, no vas a poder agregar 51. Y aquí vamos a hacer lo siguiente. Vamos a llenar esto primero. La de `numbers`. Vamos a poner `numbers.Add(1);` y así hasta el cinco. Y vamos a hacer un método que nos imprima la lista. Vamos a ponerlo aquí. Vamos a ponerle `public string GetContent()`. Y que esto nos regrese el contenido que tiene la lista. Para eso va a ser un `for` internamente. Aquí vamos a poner que haga un `for`, un `for` mejor dicho, `foreach`. Y vamos a hacer este `foreach` que trabaje sobre la lista que tenemos. Ahí vamos a poner `element in this.list`. Y listo. Aquí lo que vamos a hacer es un `string` el cual tenga el contenido y ese contenido lo vamos a retornar. Aquí `return content;`. Y aquí vamos a estar concatenando los elementos. Solamente aquí voy a poner que este valga vacío al principio. Y aquí vamos a ponerle `content += element + ", ";`. Y punto y coma. De esta manera, vamos a obtener los elementos que tiene la lista. Vamos a poner aquí `numbers.GetContent()`. Vamos a imprimirlo directamente. Vamos a poner `Console.WriteLine(numbers.GetContent());`. Y de esta manera, vamos a obtener los elementos que están ahí dentro, que sería el listado que tenemos ahí arriba.

Vamos a correr esto. Aquí no está dando un error, pero es un error común porque no ha inicializado el objeto. Creamos el objeto aquí, pero no lo he inicializado. Aquí vamos a poner `this.list = new List<T>(limit);`. Es decir, yo al momento que estoy haciendo el objeto allí arriba, no no lo estoy creando, es decir, aquí no está creado el objeto, simplemente se está reservando la memoria para una variable que va a guardar un objeto que va a ser creado posteriormente. Cuando haces el `new List<T>(limit)`, es el momento que se crea el objeto. En este punto, ya se está creando el objeto. Me marcó un error porque estoy haciendo un `Add` de un objeto que no existe, está reservado pero no existe. Y una vez estando esto ya claro, esto ya debería funcionar. Vamos a correrlo.

Vemos que nuestro código metimos 1, 2, 3, 4, 5. Pero aquí tenemos una limitante de cinco. El seis no debería estar dentro. Por lo cual, el seis no va a ser parte de nuestra lista. ¿Por qué no es parte de nuestra lista? Porque tenemos un `if` aquí que dice, si el `count` es menor al `limit`, va a entrar a esta línea. Si es ya nuestro `count` va a llegar a un punto que es cinco, ya nunca va a entrar a esta línea.

Es por eso que estamos limitándolo a cinco. Y ahí por eso que el seis nunca se ha metido. De hecho, podemos seguir metiendo información. Podemos meter un 7, 8, 9 y nunca se van a meter. Esto solamente es un ejemplo para que veas cómo se utilizan los generics, sin importar el tipo.

Vamos a correr esto y vemos que pasa lo mismo. Llega hasta el cinco y eso es correcto. Eso también funcionaría con los nombres. Es decir, si yo pongo aquí numbers, eh, es names. Otra vez dije numbers. Aquí está names. Vamos a poner add. Vamos a poner seis, vamos a poner seis nombres. Vamos a ponerlos. Vemos que tenemos seis nombres aquí. Ahora me voy a imprimir esos nombres con esta misma línea. Solamente voy voy a reemplazar numbers por name names. Y ahí está. Esto debería meter a Héctor, Ana, Luis, Juan y Roberto, pero Carla no debería meterla. Estamos utilizando el la misma clase, solamente le hemos cambiado el tipo con el generic. Hemos reemplazado el tipo, bueno, hemos enviado el tipo.

Ahora, en este caso, vamos a trabajar con lo que es el String. Y ahí tenemos, mira, está hasta Roberto. Nos ha metido el sexto que es Carla. Los generics también pueden funcionar con objetos, con clases. Por ejemplo, yo puedo tener una clase aquí debajo. Otra clase que se llame, esta clase se va a llamar Beer. Y esta cerveza va a tener un nombre y un precio.

Bien, en esta clase vamos a hacer lo siguiente. Vamos a crear una nueva colección de nuestra mylist y vamos a ponerle que esta va a ser del tipo Beer. Y vamos a poner que este objeto se va a llamar Beers. Y vamos a poner que solamente va a permitir tres cervezas. Entonces acá nosotros vamos a crear esas cervezas. Vamos a ponerle aquí Beers add. Vamos a ponerle aquí, tenemos que crear los objetos. Los podemos crear sin necesidad de guardarlos en una variable. Podemos poner aquí directamente new Beer. Y de hecho, con las llavecitas podemos poner los dos valores. Name, vamos a ponerle que esta es una cerveza, "Erdinger". Y el caso del precio, vamos a ponerle que cuesta, vamos a ponerlo en dólares, vamos a ponerle 5. Bien. Y aquí ya tenemos esto. Y vamos a agregarnos otras cuatro cervezas, porque nuestro límite aquí son tres. Vamos a agregar otras cuatro cervezas. Y listo.

Ya teniendo estas cervezas agregadas, vamos a poner esta misma línea para obtener el contenido. Y vamos a obtener los sobrevir. Aquí vamos a, vamos a ponerle Beers. Y vamos a correr esto a ver qué es lo que pasa. Debería funcionar igual, simplemente nuestra clase está reemplazando el tipo ahora por una clase. Y esta clase le va a dar el tipo. Aquí vemos que podemos ver que nuestra, nuestra, bueno, aquí el punto es que tiene name, Beer, Beer, Beer, Beer. Esto pasa porque es un objeto. Entonces los objetos no tienen, eh, en sí, no tienen el el dato como tal como en los tipos nativos. Pero esto se puede solucionar.

¿Recuerdas que hablamos de la sobreescritura de lo que que heredas en C#? Todas las clases, aunque tú no lo especifiques, heredan de Object. Object lo que tiene es un método, se llama ToString. Si vemos aquí, hay un método llamado ToString. Parece que no lo podemos ver porque es un partial class. Las partial class es algo de C# que no necesariamente tenemos que verlo aquí, pero tú puedes definir una clase con varios archivos. Bueno, el punto es que todos los objetos tienen un ToString ya definido. Ese ToString, si tú no lo defines, te va a dar el nombre de la clase. Por eso salió Beer, Beer, Beer, Beer. Nosotros podemos sobreescribirlo haciendo lo siguiente: override string ToString. Y de esto, de esta manera, podemos nosotros reemplazarlo. Aquí me ha sugerido código, pero esto está mal. Yo quiero que aquí me mande el nombre de la cerveza. Entonces, poniendo name, así tal cual. Aquí esto está sol, sale sobrando, es de ToString que está ahí. Así de esta manera, automáticamente nos debería agarrar el, directamente en lugar de poner Beer, Beer, el nombre de la clase va a poner el nombre de nuestra cerveza. O igual lo podrías componer con más información. Por ejemplo, podemos ponerle aquí un más. Pues pod poner los paréntesis. Aquí vamos a ponerle aquí un más y vamos a ponerle también el precio. Podemos poner toda esta información. Y este ToString es el que va a tomar en este punto este Element, va a tomar ese ToString, eh, directamente y ya no va a tomar el nombre de la clase.

Si esto lo ejecutamos, vamos a ver que ahora nuestra información va a ser la que nosotros hemos puesto. Aquí vamos a ver la información. Debería salir nombre Erdinger, precio 5. Nombre Corona, precio 1. Nombre Delirium, precio 10. Pero no sale la cuarta cerveza. Es decir, la cuarta cerveza, la Paulaner, no sale. Es porque tenemos utilizando nuestro mylist, que tiene un límite de tres. Y vemos que funcionan los generics, tanto para enteros, strings, o tus objetos, tus clases definidas. Entonces, esto te da muchísima posibilidad para trabajar.

En esta clase vamos a ver el concepto de serialización y deserialización de objetos. Ya vimos en clases pasadas cómo era el formato JSON. JSON, y que es un formato para poder pasar información entre lenguajes de programación o distintas tecnologías. Y te indiqué que una vez que tenías el JSON, podías transformarlo en tu lenguaje de programación a objetos y de esta manera ya poder trabajar con ellos dentro de tu lenguaje de programación. Bueno, el punto es cómo transformas un objeto a JSON y cómo transformas JSON a objeto. Que también otro punto a a recalcar aquí es que JSON es uno de los tantos formatos a los cuales puedes serializar un objeto. Puedes realizarlo también a a bytes, por ejemplo, o puedes realizarlo a otros formatos. Pero en este punto vamos a a ver JSON, ya que es lo que nos va va a estar relacionado a nuestro curso de backend.

Bien, teniendo esta clase que tiene dos propiedades, una llamada nombre y otra age, vamos a crear un objeto de ese tipo de clase. Escribiendo nuestro nombre, en este caso voy a poner mi nombre, Héctor. Y vamos a poner new People. Y hay una forma para llenar estas propiedades en automático desde la creación, sin necesidad de un constructor, que es escribiendo las llaves y poniéndolas cada elemento. Por ejemplo, nombre, vamos a ponerle aquí que es un String, "Héctor". No coma, y seguido de la otra propiedad que se llama age, y vamos a ponerle 30. Se bien. Teniendo esto, ya tenemos un objeto llamado Héctor, el cual vamos a necesitar. Vamos a serializar a JSON. Para serializarlo a JSON, necesitamos guardar ese JSON en un String. Pero antes, para utilizar eso, necesitamos importar una biblioteca que ya está en C# llamada System.Text.Json.dll. Con la palabra using, podemos utilizar todo lo que está dentro de esta biblioteca, que ya está dentro de .NET. No es algo que yo haya creado. Y esa nos va a dar el funcionamiento necesario para eso.

Vamos a utilizar una clase llamada JsonSerializer. Y esta tiene un método estático. Los métodos estáticos en las clases no necesitan de un objeto. Es decir, el método estático y las propiedades estáticas van directamente de la clase. Yo, si quisiera tener un método estático aquí o una una propiedad estática, vamos a crearla aquí: public static string Get. Y vamos a poner que esto te retorne, eh, "Hola". Yo puedo crear estáticos de esta manera, simplemente escribiendo aquí static. Y para utilizar yo este método, no necesito crear un objeto. Directamente yo escribiendo la la clase People.Get, ya tengo eso. Es decir, lo que es estático, tanto métodos en este caso como propiedades, es pertenece a la clase. Puedes invocarlo directamente sin crear un objeto. No necesitas crear un objeto como en este caso que creé Héctor new People. No necesitas de eso.

Bien, y la otra cosa que te llame la atención es este este símbolo. Este símbolo lo que se utiliza es cuando solamente tienes una línea de código en tu método. Puedes escribirlo con las clásicas llaves así y poner el return y poner la llave, como lo hemos hecho en los otros ejemplos. Pero si es solamente una línea, puedes abreviarlo directamente escribiendo el símbolo que vimos antes. Aquí solamente falta el punto y coma para que no marque, pero puedes ahorrarte todo esto escribiendo azúcar sintáctica de la siguiente manera: el símbolo igual mayor que y tu retorno, que tiene que ser el mismo tipo que estamos escribiendo aquí.

Bien, teniendo esa explicación del static, ya puedes entender que JsonSerializer tiene un método llamado Serialize, que el cual es estático. Y aquí vamos a mandar a Héctor. Y ahí está. Y este JSON, si yo lo imprimo con Console.WriteLine para salir a pantalla, vamos a ver que JSON va a tener la información, pero en de People que tenemos aquí arriba, de Héctor, age 36, pero en formato JSON. Vamos a correrlo. Y aquí está. Perfecto. Este símbolo que es es por el acento. No te asustes, está bien, está perfecto. Esto. Ahí está, es un formato JSON. Te fijas.

Vamos a copiarnos este JSON, editar, copiar. Y ahora vamos a hacer lo contrario. Vamos a guardar ese JSON que acabo de hacer, pero voy a cambiarle el nombre. Vamos a ponerlo aquí abajo. Vamos a guardarlo en un String, myJson, lo llamaré. Y vamos a poner aquí un array. Vamos a poner dos comillas. Y esto nos permite poner strings en en distintas columnas. Ya podemos escribir directamente strings en en diferentes filas. Y aquí simplemente voy a poner esta comilla aquí para que se vea que es la llave. La he acomodado como un JSON ya más para que pueda ser detectado. Doble comilla. Por qué. Porque tenemos una comilla de apertura y otra de cerradura. Para que C# sepa que esto es un símbolo de comilla. Doble comilla se pone doble comilla. Una la que le indica que es el símbolo y la otra le indica que ahí viene un símbolo que utiliza en su formato para para detectar strings. Okay, pero es es parte del String. La comilla es parte del String. Por eso se pone doble. De esta manera, si C# ya sabe que aquí name, entre name, entre al inicio de name y al final de name, hay una comilla. Y mismo caso para age. Y mismo caso para este String que tenemos aquí de Héctor. Y bien, ya teniendo esto.

Aquí igual puedo ponerlo ya directamente. El acento igual va a funcionar. Aquí el acento. Bien, teniendo esto, yo ahora voy a hacer el caso contrario. Voy a crear un objeto del tipo People. Vamos a poner aquí People. Igual puedes poner var nada más. Estoy haciendo ciertas modificaciones en cómo declaro los objetos para que veas que se pueden declarar de distinta forma. Vamos a llamarle, vamos a llamar este distinto para que sepamos que es otro. Vamos a llamarle Juan. Y aquí vamos a llamarle People a Juan. Es igual. Y en este caso, vamos a hacerlo el caso contrario. Vamos a utilizar la misma clase llamada JsonSerializer. Punto. Y en este caso, en lugar de serializar, vamos a deserializar. Deserializar es a partir de un JSON o a partir de un formato construir el objeto. Y aquí tenemos People. Y tenemos myJson. Y de esta manera, Juan debería tener el ser un objeto. El cual yo al momento que ponga name, debería tener el nombre. Al momento que ponga age, debería tener la edad. Entonces, aquí vamos a poner Juan.name. Y vamos a poner Console.WriteLine(Juan.name). Lo cual me debería mostrar la el nombre y la edad. Al ejecutar yo ejecuto esto y vemos que a partir de un de un objeto hemos creado un JSON. Y a partir del JSON hemos obtenido la información para tenerla en un objeto de C#. El proceso es el siguiente: un objeto cuando se serializa, es convertirlo a un objeto de C#. Se utiliza Deserialize. De esta manera, esto que se pone verde es una advertencia de que dice que este JSON myJson podría ser null. El momento que podría ser null, pues bueno, yo aquí le pongo que People también podría ser null. Y aquí te seguir marcando. Entonces, Juan podría ser null. Y Juan de abajo también podría ser null. Estos son advertencias. Para que C# te está indicando que hay una posibilidad de que venga que myJson esté vacío. Es decir, podría estar así, podría estar así, eh, sin esto. Y eso ocasionaría que Juan estuviera nulo. Nulo es que es un objeto en memoria, pero no tiene nada. Y aquí el punto es que si Juan es algo que puede ser nulo, por lo cual aquí C# al momento que tú le pones el símbolo de interrogación, le estás indicando que podría ser nulo. Por lo cual, con eso se protege C# para que no marque ningún error. Es decir, si yo esto lo transformo, vamos a quitar todo esto, vamos a ponerlo nulo. Esto ya en ejecución no me ocasionará error porque Juan ya se está evaluando que okay, puede ser nulo. Y C# ya sabe que podría ser nulo. Por lo cual no va a arrojar una excepción, un error. Va a correr el programa tal cual, porque estás advirtiendo a C# que podría ser nulo. Es por eso que sale verde. Te fijas, corrió sin problema alguno, nada más porque borré la la línea de serialización. Por eso no salió la información de Juan, pero sí el punto es que, eh, cuando estemos utilizando el backend, vamos a trabajar mucho con JSON, pero en el backend, también el mismo framework ya va a estar haciendo este trabajo de serializar y deserializar por nosotros. Pero es bueno que entiendas el proceso, porque tarde o temprano lo vas a necesitar, independientemente que estés programando backend. Esto es algo universal, videojuegos, internet, las cosas, donde sea. JSON es un formato que está en todos lados.

En esta clase vamos a ver ciertos conceptos de programación funcional que son necesarios para entender conceptos del backend que vamos a ver más adelante. No vamos a adentrarnos tanto a programación funcional, pero ciertas cositas. Primero, función pura. Una función pura es una función la cual no altera cosas exteriores a ella y la cual, recibiendo siempre el mismo valor, va a retornar lo mismo. Es decir, teniendo la siguiente función, la cual va a restar dos números. Esta función tiene como parámetro de entrada dos elementos. Si tú mandas un uno y un dos, para que sea función pura, siempre tiene que retornar el mismo valor. Es decir, en este caso, te debería retornar, si este recibe un dos y luego un uno, te debería retornar un uno. Y si tú ejecutas esta función con lo mismo, un dos y un uno, 10 años después, debería regresarte igual el mismo valor, uno. Una función pura es la que te regresa siempre lo mismo, dando los mismos elementos de entrada. Es decir, si yo ejecuto esta función, la ejecutamos de la siguiente manera, poniendo aquí el dos y el uno. Esta función, si yo la ejecuto hoy, me va a retornar un uno. Si la ejecuto mañana, me va a seguir retornando un uno. Esta función es una función pura porque cumple con los dos objetivos: retornar siempre lo mismo cuando tiene los mismos valores de entrada y no alterar un elemento exterior.

Lo aquí, si tuviéramos de repente un Random o algo que tiene que ver con la fecha, esta función no sería función pura, ya que internamente estaría haciendo cosas que van a cambiar. Es decir, si tú ejecutas esta función hoy, mañana va a tener otro valor porque está basado en la fecha, por ejemplo, o en un Random, un número aleatorio. Por ejemplo, una función que se llame tomorrow. Es una función en este caso que te regresará el día de mañana. Esta función no es una función pura. ¿Por qué? Porque si yo ejecuto esta función hoy, me va a dar, me va a retornar el día de mañana. Pero si esta función la ejecuto mañana, me va a retornar otro valor, que es pasado mañana. Esta función no cumple con una función pura. ¿Cómo se arregla esto? Bueno, hacemos que el valor del día, en este caso, se reciba aquí. Y de esta manera, nosotros ya esta función ya no tiene la responsabilidad de obtener el día de hoy. Es decir, si yo le mando aquí el día de hoy, este día me retornará el día de mañana. Si le mando nuevamente en una semana el mismo día de hoy, me retornará el mismo valor, ya que esta función ya ahora sí no depende de un elemento calculado internamente, sino que externamente le estamos dando la fecha. Y de esta manera, la función sí, ya en este punto, sí cumple con ser una función pura.

Y he puesto este ejemplo a drede, porque muchos a lo mejor se preguntarán que tengan un poco más de experiencia, dirán, "Oye, pero DateTime es un objeto, esto está pasado por referencia, por lo cual está modificando el objeto, por lo cual no cumpliría con el concepto de función pura de que no altera los elementos externos". Es decir, si yo tengo un DateTime afuera, muchas personas creen que el DateTime en C# es un objeto y no, o es una clase. Y DateTime en C# no es una clase, DateTime en C# es un struct. Un struct, ¿qué es? Es un elemento en C# el cual se pasa por valor, no por referencia. Es decir, que yo cuando estoy pasando este date aquí, se pasa su valor, no se pasa la referencia como pasa en los objetos. En los objetos, si DateTime fuera un objeto, este date que está aquí, aquí sí se alteraría el objeto en sí. Pero en este caso, como es un struct, DateTime sigue respetando a que se pase por valor. Por lo cual, esta función sigue siendo una función pura. Esta función, si yo la, este Console.WriteLine, si ejecuto esta función GetTomorrow con el mismo valor de date, es decir, el mismo valor de date de hoy, o en este caso, ejecuto algún objeto, bueno, un objeto, alguna variable que tenga sea el tipo DateTime, la cual tenga un elemento del primero de octubre 2023, se la mando a GetTomorrow, esta función va a seguir siendo pura. Por si sigo ejecutando con este mismo valor 5 años después, esta función GetTomorrow me retornaría lo mismo, ya que ya no está dependiendo de un cálculo interno y está dependiendo del valor que se le otorga. Sigue respetando el concepto de función pura.

Si tú cumples con este este objetivo de función pura de seguir, eh, que no alteres lo que está externo o que, eh, tengas el siempre el mismo resultado, dada la dada la misma entrada, vas a tener una gran ventaja cuando estás haciendo programación concurrente, porque la programación concurrente y ese cambio de estados de elementos que tienes que rastrear a ver dónde se cambió, ya cuando tienes programación, eh, funcional funcionando con estos principios, vas a evitar muchos problemas. Por ejemplo, buscar quién es el que cambió algo, ya que como algo, estas funciones puras no modifican algo externo, entonces es más fácil rastrear cuando estás trabajando con concurrencia, con muchos hilos.

Y aquí tú me dirás, "Oye, ¿qué pasa si yo sí quiero modificar un nuevo valor internamente?" O sea, es decir, tenemos una clase, teniendo esta clase Beer, la cual vamos a crear un objeto de esa cerveza, la cual tiene como una, el valor tiene Guinness en este caso, y vamos a crear una función la cual haga es que las las letras de ese nombre se haga en mayúsculas. En esta función, lo que hace es recibir una cerveza y retornar una cerveza, la cual se le hace que el nombre sea mayúscula. El problema de esta de esta función radica en que no es una función pura, ya que si yo imprimo el nombre aquí, si yo ejecuto esta función y esta función, por lo cual me retorna una cerveza, por lo cual va a tener una propiedad llamada name, la cual va a estar transformada en mayúscula, y ejecuto el Beer que está externo, es decir, el que está exterior, una función pura no debería alterar el elemento externo. Por lo cual, esta función, si yo la ejecuto, vamos a ver que ha modificado también al externo. El elemento externo, estoy imprimiendo y vemos que también se ha hecho en mayúscula.

Entonces, ¿qué es el qué es lo que se hace en estos casos? Bueno, puedes optar por una técnica que sea clonar el elemento o en este caso, en C#, existen unos elementos llamados Records. Estos Records tienen ciertas cualidades también para clonarse y son inmutables, es decir, ya por la misma esencia del Record, ya no lo puedes modificar. Y si quieres un nuevo valor en ese Record, se clona. Entonces, optas por una de esas técnicas. En este caso, como es una clase que solamente tiene una propiedad, pues bueno, podemos crear un nuevo objeto aquí. Podemos crear un nuevo objeto, eh, vamos a poner Beer2 es igual a new Beer. Y aquí simplemente vamos a ponerle que el name es igual al no, al Beer que estamos recibiendo, name.ToUpper. Entonces, de esta manera, estamos trabajando con otro objeto. El cual, simplemente vamos a quitar esta línea, vamos a retornar en lugar del objeto original. Y de esta manera, vamos a ponerle aquí, esto quitarlo y vamos a ponerle return Beer2. Y de esta manera, ya no se va a ejecutar, eh, no se va a modificar el elemento externo. Por eso, estos tipo de prácticas, estos tipo de principios de programación funcional son útiles, ya que si tú sigues respetando, vemos aquí que el objeto de afuera sigue teniendo las minúsculas, pero el nuevo objeto tiene mayúsculas. Hemos respetado que el elemento externo no se haya modificado. Siguiendo este tipo de principios, puedes, eh, evitar muchos problemas, sobre todo cuando estás trabajando con concurrencia o con mucha data, está rastreando cuál del todos los hilos en paralelo está modificando un estado. Imagina, es muy difícil. Entonces, cuando estás utilizando estos principios de programación funcional, va a ser más fácil.

Los siguientes conceptos que son útiles de programación funcional: saber que hay un, una función puede guardarse en una variable. Eso se llama función de primera clase. Una función tal cual, así, vamos a poner show. Esta función puede guardarse en una variable. Vamos a imprimir aquí un mensaje y ese mensaje lo vamos a recibir como parámetro. Ahí está. Esta función como tal, yo puedo guardarla en una variable llamada show minúscula, es igual a show, sin poner los paréntesis. Es decir, aquí no estoy poniendo los paréntesis, simple, simplemente estoy poniendo el nombre de la función. Y ya está. Yo puedo ejecutar show aquí. Puedo ejecutarlo. Y ese show lo que va a hacer es recibir, obviamente, un mensaje, "Hola", y esto va a funcionar sin problema alguno. Pero el que estoy ejecutando es la variable, no estoy ejecutando la función. Esto es una de las cualidades que tienen los lenguajes de programación más reconocidos: JavaScript, Python, Java, C#. Y vemos que es posible guardar una función en una variable. Ese concepto se llama función de primera clase.

Ahora, si tú puedes guardarla en una variable, también puedes mandarla como parámetro. Por ejemplo, lo siguiente. Vamos aquí poner, vamos a crear una función que se llame SomeAlgo. Y en C#, tenemos que tipar las funciones. Por lo cual, aquí vamos a poner que esta va a ser un tipo Func. Bueno, un tipo, sí, Func. Y este Func, no, en este caso, es un Action. Ahorita vamos a explicar eso más detalle. Un tipo Action. El tipo Action es una función que recibe elementos, pero no retorna nada. Esta cumple con eso. El tipo Action recibe elementos, pero no retorna nada. Es tipo void. Entonces, este Action, lo que vamos a especificar en su, dentro de sus generics, es vamos a especificar qué tipo es el que recibe. En este caso, es un String. Si recibiera otros tipos, pues se pone coma y más tipos, no, los que tú desees, dependiendo tu situación. En este caso, vamos a ponerle aquí FN. Y esta función Z va a hacer algo al inicio, hace algo aquí, y también, y a medias, va a ser esta ejecución de la función. Si vemos que Action está definiendo que no retorna nada, pero sí recibe un String, tenemos que mandar ese String. Y ese String nosotros lo podemos recibir aquí. Por ejemplo, mira, message. Y lo podemos mandar ese message aquí. Y podemos poner algo posterior. Este tipo de cosas sirven mucho para cuando queramos que nuestra función tenga más flexibilidad en su ejecución. Es decir, hago algo al inicio, hago algo a medias, hago algo al final, o quiero que hagas algo hasta que termine. Cosas así. Eso es llamado callback. Hacer algo cuando termine. De esta manera, vamos a poner aquí: "Hace algo al final", "Hace algo al inicio", y "Hace algo al final". Y bien, vamos a quitar este show que está aquí. Y como ya lo tengo guardado en la variable, vamos a hacer lo siguiente. Vamos a ejecutar Some, mandándole mi variable show y mandando un mensaje, "Hola, ¿cómo estás?". Y esto lo ejecutamos. Vamos a poner punto y coma. Lo ejecutamos y vamos a ver el comportamiento de una función. Esta función Some es una función de orden superior, una función que recibe funciones como parámetro. Y vemos que la función que estamos recibiendo viendo como parámetro, la cual se llama show, está mostrando el mensaje que estamos poniendo a la derecha. Este tipo de cualidades nos da muchísima ventaja para cuando estamos programando funciones para que esas funciones puedan tener un comportamiento más flexible, más dinámico. Por ejemplo, yo no sé qué haces aquí. Yo sé que tengo que mandarte un String y tú haces lo que, bueno, tú haces algo. Ahora, imagina que yo quiero hacer este show no haga un Console.WriteLine, sino que retorne ese mensaje en mayúsculas. Vamos a ponerlo aquí: return. Y vamos a ponerle message.ToUpper. Y de esta manera, nuestra nuestro mensaje, este String, igual mismo caso con DateTime. Cuando tú mandas un String, este en este caso es un Class. Y aquí es donde muchas personas se confunden. Pero String es tiene un comportamiento particular. Aquí entra de repente mucha confusión porque dicen, "Okay, hiciste una clase llamada cerveza y la mandaste como referencia, la mandaste como parámetro, y vimos que si la modificaste internamente, como en este caso, la función, bueno, se se ha, se modificó el elemento, no se modificó el objeto". Bueno, en el caso de String, lo que pasa es que es inmutable. String por sí mismo no se modifica nunca. Lo que hace String es hacer un, aquí en este caso, ToUpper es inmutable. ToUpper lo que hace es hacer un nuevo String. Por lo cual, mi message que está original, si lo tuviera una variable, no se modifica, simplemente crea uno. Los strings son inmutables y todo lo que se hace sobre un String es un nuevo String el que se te da como resultado.

Bueno, en este caso, ya teniendo esto, bueno, show ya no, no respeta este tipo de función, ya que el Action es toda función que no retorna algo. Hay un tipo en C# que es para cuando una función retorna algo y puede recibir parámetros. En este caso se llama Func. Este Func es el tipo de funciones que sirven en C# para especificar qué es lo que va a salir. Bueno, va a salir un String. Y qué es lo que recibes. Bueno, otro String. Y de esta manera, si vemos aquí la definición, nos dice que la salida es el último elemento. El último elemento que tú especifiques aquí va a ser el tipo de dato que retornas. Y los demás elementos que están antes son los tipos de datos que recibes como parámetros. Por ejemplo, en este caso, recibo un String, un int y un int, pero retorno un String. Aquí podemos ver la definición. Y bueno, en este caso, esta función solamente respeta el que recibe un String y retorne un String. Y de esta manera se quitan los errores. Te fijas, ahora Some no imprime nada, retorna un String. Por lo cual, aquí puedo poner un Console.WriteLine. Y vamos a ponerle aquí dentro, vamos a ponerle que nos haga este "Hola, ¿cómo estás?" Y que haga toda la ejecución. Bueno, aquí no era eso. Esto es acá. Aquí no era eso. Esto es aquí. NFN message, porque aquí está el Func, el cual recibe un parámetro, el cual retorna un String. Y este FN message está retornando un String, el cual puedo imprimir en Console.WriteLine. Y de esta manera, yo igual puedo imprimirlo así, o puedo guardarlo en una variable. Puedo hacer lo que yo guste. Y bueno, ya ejecutamos esto y vemos que nuestra función está ya funcionando con éxito. Bueno, en este punto, en C#, tenemos que tipar las funciones. Tú, si tu función va a retornar algo, utilízala. Nada, utilízate. Programación funcional, ya que cuando estemos trabajando ya ahora sí en el proyecto de backend, vamos a ver funciones que reciben otras funciones. Y de esta manera, pues ha quedado más claro.

En esta clase vamos a ver las expresiones lambda. Que las expresiones lambda tienen su equivalente en otros lenguajes de programación, donde en otros lenguajes de programación se llaman arrow function, funciones flecha. En sí, ¿qué son? Es una forma de expresar, escribir una función que es anónima. Y ¿qué es una función anónima? Bueno, una función que no necesita declararse, no necesita crearse. Es decir, una función la cual no tiene nombre, pero sí tiene definido qué es lo que hace. Esto nos da una facilidad para no tener que estar creando funciones que a lo mejor solamente vamos a ejecutar una vez o que van como parámetro en una función de orden superior. En este punto, es más que nada esa particularidad o ese beneficio que tenemos de no tener que escribir funciones de más cuando solamente se van a ejecutar una sola vez y van como parámetro en otra función de orden superior.

Para escribir una función lambda, basta con que pongamos el tipo que tiene. En este caso, vamos a hacer una función lambda la cual reciba dos valores y y retorne un nuevo valor. Esta función lambda la vamos a llamar, eh, vamos a llamarla que sea la resta, lo que ya hemos visto. Y simplemente se expresa con la siguiente forma: poner paréntesis. Y estos paréntesis van a especificar, eh, que es la función, la entrada de esta. Vamos a poner qué es lo que va a definir qué es lo que va a entrar en esta función. Bueno, vamos a definir que el primer parámetro es una un entero, el segundo parámetro es un otro entero. Y esto lo que va a hacer es restarle a la B. Y es todo. Así es como se se escribe una expresión lambda. Si te fijas, esto es lo mismo que escribir esto de aquí abajo. Es lo mismo. Pero imagina que no, no tuviéramos las expresiones lambda, tendríamos que hacer esta función. Cuando la podemos expresar rápidamente de esta manera.

Ahora, hay cosas que han ido mejorando en C#. Por ejemplo, si tú ya definiste que aquí va a ser entero, esto ya C# lo conoce. Es decir, no necesitamos ponerle aquí entero y entero. Ya es como de una manera, ya lo sabe porque tú lo especificas en este punto. Entonces, ya sabe que lo que escribes aquí van a ser dos enteros. Entonces, nos reduce más el código. Cuando tú tienes una función la cual solamente tiene un parámetro, en este caso, vamos a poner uno y vamos a retornar un parámetro, un valor. Y esta función que hace algo, imaginemos que hace una multiplicación. Vamos a especificar los paréntesis, vamos a especificar el parámetro y vamos a hacer el A por 2. Aquí, cuando tienes un parámetro solamente en tu función, no necesitas poner los paréntesis. Aquí podemos quitarlos. Igual se reduce mucho más el código.

Va a haber situaciones donde tu función va a ser, eh, va a ser necesario escribir más de una línea de código. En el caso siguiente, por ejemplo, tenemos esta Some2. Vamos a poner que es que tiene una sola, un solamente un parámetro. Y esto, pues, vamos a ponerle más líneas de código. Pues puedes poner las llaves, tal cual como se hace una función normal. Y aquí solamente vamos a poner que está, vamos a poner un return A por 5, no sé, algo por decir algo que va a hacer aquí. Vamos a poner aquí que A es igual a A + 1. Y A tienen más líneas de código. De esta manera, tú puedes especificar más líneas de código agregando tus llavecitas. Y para ejecutar esto, tal cual, igual que una función, pones esto. Recuerdas, la expresión lambda es solamente esto de la derecha. Es esto de la derecha. Es esto de la derecha. Si recuerdas, esto ya es una función que se puede guardar en una variable. La variable se llama S, Some, Some2. Y simplemente la ejecutas tal cual fuera una función. Así, tal cual, ponemos op, ponemos un cuatro, y se ejecuta tal cual una función.

Pero bien, ¿cuál es el beneficio en sí más claro? Es cuando tienes una función la cual recibe funciones. Una función de orden superior, por ejemplo, tenemos una función llamada Some, la cual tiene un tipo de función, la cual va a retornar un entero y va a recibir dos enteros. Se llama FN. Y aquí vamos a especificar una entrada de número. Esta función lo que va a hacer es simplemente ejecutar este FN, lo va a ejecutar, estar aquí dentro, y vamos a mandarle el número que estamos recibiendo dos veces. Y esto lo vamos a guardar en una variable, la cual se llame, en este caso, resultado. Y ahí está. Nuestro resultado va a guardar esto, el resultado de esta función, que este resultado en sí es un entero. Igual podemos definirlo. Igual, ya sabes que en C# puedes poner var. Bien. Y esta función, aquí es donde viene el beneficio de los arrow function o de las expresiones lambda. Expresiones lambda, como las vas a encontrar en C#, cuando yo quiero ejecutar esta función, no necesito crear una función para que pueda pasársela como parámetro. Puedo poner la expresión lambda directamente aquí. Por ejemplo, sabemos que tiene que va a recibir dos parámetros de enteros. Vamos a ponerle aquí que recibe un A, un B, y vamos a ponerle que ese A y ese B va a hacer lo siguiente: va a sumarlos. Ahí está. A y B los va a sumar. Y la función Some recibe un segundo parámetro que es un valor, un número. Y de esta manera, vemos que lo va a recibir el cinco en el number. El number va a mandárselo a la función que ha recibido como parámetro. Esta función que ha recibido como parámetro es una expresión lambda. El cinco va a ir tanto en la A como en la B. Y aquí va a ser 5 + 5, va a ser 10. Entonces, tu resultado en result va a ser un 10. Si yo ejecuto esto, vamos a ver que vamos a tener un 10 en result. Cuando yo pongo esto a la izquierda, esto rojo es para debuggear, para de depurar, para ver en tiempo de ejecución qué es lo que tienen los elementos en ese momento. Yo estoy corriendo el proyecto y cuando esto esté corriendo, vamos a ver aquí todo un esquema de resumen de qué es lo que está en esa línea. Y vemos que aquí en esa línea vemos el resultado. Aquí vemos aquí abajo que result tiene un 10, tal como lo vimos. Y si yo pongo el cursor aquí, vemos el valor que tiene la variable, mira, 10. Si lo, si ponemos el cursor aquí, vemos que es un cinco, es un cinco. Entonces, es muy útil también saber depurar el código para ver qué es lo que está pasando en tiempo de ejecución.

En esta clase vamos a ver algo llamado LINQ. Link, o LINQ, como quieras decirle. Y LINQ es una extensión al lenguaje de programación C#. LINQ lo que hace es trabajar con colecciones de manera declarativa. Es decir, si tú has utilizado SQL, imagina que puedes, eh, escribir algo muy parecido como SQL en C#. Por ejemplo, vamos a tener aquí una una lista de que puedes trabajar con las colecciones en sí. Vamos a tener un una lista de nombres. Vamos a poner aquí numbers, eh, digo números, no, de nombres, names. Y vamos a poner que sea una lista de tipo String. Y vamos a poner los valores de una vez con las llavecitas. Podemos ponerlos aquí. Vamos a poner algunos valores. Y LINQ, ah, ahí donde entra a poder hacer un gran poder, porque LINQ nos permite trabajar con colecciones para poder hacer ordenamientos, filtrados, eh, selección de algunos elementos. Nos permite hacer lo que hacemos con SQL, tal cual, con las colecciones.

Cuando estás trabajando con LINQ, hay dos partes que tenemos que tener muy entendidas. Una es el origen de los datos. Podría ser un XML, podría ser un JSON, podría ser muchísimos tipos de colecciones. Pero cualquier colección puede trabajar con LINQ. En este caso, vamos a trabajar, por ejemplo, yo quiero que esto me me lo retorne ordenado. Por ejemplo, que vamos a poner var names2, o names result, vamos a llamarle. Y esto es igual a, en este caso, vamos a poner, vamos a comenzar con la palabra from. Vamos a poner un alias, un alias a nuestra colección. En este caso, voy a ponerle, vamos a poner la palabra reservada in, y enseguida el origen, en este caso, names. Yo quiero ordenar esto. Vamos a poner order by, pegado, order by. Y vamos a ponerle sobre qué campo lo vamos a ordenar. En este caso, es solamente tenemos un elemento en la colección, que es el valor mismo, String. Si tuviéramos objetos, podríamos especificar por cuál elemento del objeto, ya sea el nombre, ya sea la edad, etcétera. Pero en este caso, en sí mismo, la colección es un String. Y bueno, y por último, vamos a seleccionar los elementos. En este caso, mismo caso, solamente tenemos puros strings, por lo cual solamente podemos seleccionar el valor por sí mismo. Y esto, si yo lo imprimo, vamos a hacer un foreach. Lo vamos a imprimir. Y este foreach va a ser el, vamos a retornar, vamos a mostrar los elementos que tienen como resultado, en este caso, names result. Y vamos a ponerlos aquí. Y vamos a poner name. Y vamos a ver cómo esto ya va a ser mostrado ordenado. Si yo ejecuto esto, vamos a ver que esto ya está ordenado. Vemos que aquí con éxito se ha ordenado alfabéticamente: Ana, Francisco, Héctor, Hugo, Pedro.

Ahora, si yo quisiera ordenarlo al revés, basta con que ponga aquí descending. Y de esta manera, ya automáticamente, bueno, aquí no es, es acá, es completamente descending. Y de esta manera, ya va a aparecer los nombres en forma descendente. Y ahí podemos ver que ahora los nombres han mostrado descendentemente. Si podemos observar, aquí estamos trabajando con unos nuevos resultados, es decir, LINQ está retornando una nueva colección, la cual está guardando names result. La colección original final no ha sido modificada. LINQ tiene tres partes. Habíamos mencionado que tiene el origen de datos, que es este, en este caso, la array. La consulta. Esta consulta, en este punto, no se ha ejecutado. Esta consulta no se ha ejecutado. Se ejecuta en el momento que haces el foreach. Y esas son las tres partes principales del LINQ: tener un origen, tener una consulta, y la ejecución de esta. Si tú quieres que esta ejecución se haga directamente aquí, ya en este punto, puedes ejecutarlo directamente con tu list. Pones tu list. Y esto ya va a ejecutarlo en este punto. Y aquí simplemente lo vamos a imprimir.

Pero ten cuidado cuando tienes colecciones muy grandes. Bueno, en este punto, esto va a ser bueno, va en el rendimiento, pues va a ser las operaciones en este punto, en lugar de hacerlo en el forage, tenerlo en cuenta nada más.

Con LINQ también podemos hacer lo siguiente. Por ejemplo, yo quisiera hacer un `Where`. Vamos a hacer un `Where` aquí. En este caso, aquí arriba, vamos a poner `trae los que tengan en este caso un nombre que tenga eh una longitud mayor a a tres. Bueno, tres. Ahí está. Y de esta manera vamos a obtener los nombres que tengan una longitud mayor a tres, tres caracteres. Y vemos que en este caso nos retorna a Ana porque Ana no supera los tres caracteres. Son las cosas que puedes hacer con LINQ.

También podremos hacer operaciones aquí de eh, por ejemplo, un `AND` y un `OR`. Operadores para poder decir, okay, quiero que sean superiores a tres caracteres y que sean menores a cinco caracteres. De esta manera nos va a obtener. Podemos hacer nosotros varias sentencias de filtrar para que podamos hacer consultas más parecidas a como SQL. Y podemos tener varios factores para el filtrado de nuestros valores. En este caso, vamos a ver que nos va a retornar todos los mayores a tres pero menores a cinco. En este caso, solamente Hugo cumple con eso.

Con LINQ también puedes hacer agrupados `Group`. También puedes trabajar con objetos. En este caso, estamos trabajando con `String`. Más adelante, cuando estemos en el curso de backend, vamos a ver como más a profundidad LINQ. Solamente quería ya decir esto básico para que se entienda y no sé, sea confuso leer este tipo de cosas o decir, eso qué es o o qué es. Se me hace muy raro porque otros lenguajes de programación no tenemos este tipo de extensiones.

Y bueno, hay otra de las cosas que hay que rescatar aquí en este en esta clase, que es que LINQ al final todo esto lo transforma a funciones. Es decir, yo puedo escribir eso con funciones. Vamos a poner `nameResult2`. Y esto yo lo puedo escribir directamente con funciones. Simplemente con `names.Where`. En este caso, hacemos un `Where`. Y en ese `Where` aquí, este `Where` recibe una función. Es decir, `Where` es una función de orden superior, la cual recibe una función. Nosotros podemos especificar funciones anónimas, llamadas como error function en JavaScript. En C# se llaman expresiones lambda. Y le vamos a especificar esta función. Recibe un elemento. Este elemento es algo. Y ese elemento vamos a llamarle `n`. Y ese elemento yo quiero que me retornes lo que sea `n.Length > 3` y también `n.Length < 5`. Estoy poniendo la misma consulta de arriba pero con funciones.

Y enseguida quiero que me pongas en ese un ordenado por descendentemente. Aquí vemos que está descendentemente por nuevamente una una función de primer orden de de primera clase. Aquí vamos a ponerle por cuál campo. Bueno, por la misma `n`. Y ya está. Ahí tenemos lo mismo de arriba y se le simplemente ejecutado con funciones. El compilador lo que hace al final es transformar todo esto a algo como esto. Y esto es lo que realmente se ejecuta en C#. Es decir, lo de arriba solamente una forma para que sea más fácil para el programador que viene de SQL entender qué está haciendo su consulta. Y esto es la forma como C# al final lo va a ejecutar.

Y ya por último, simplemente ponemos el `Select`. Que vamos cuando tenemos varios elementos, por ejemplo, un objeto que tenga varias propiedades, podemos seleccionar ciertos campos de ese objeto. Tenemos un objeto que tiene tres propiedades: nombre, edad y país. Podemos decir, okay, creo que la colección me regresa solamente los nombres. Entonces aquí ponemos `Select d => d.Name`. De esta manera, esto es una función anónima. Es una función eh prácticamente que se eh se evita escribir acá arriba. Yo podría escribir la función aquí arriba, pero evito escribirla ahí porque simplemente la estoy ejecutando aquí y no la necesito más. Esta función lo que especifica es que está retornando la colección como tal. No estoy seleccionando elementos en específico. En este caso, los elementos únicos que hay son strings. Es decir, no son objetos, no son objetos con más eh valores que más que el mismo valor por sí mismo, el string.

Bien, aquí ya teniendo este apartado, vamos a ver que tenemos el mismo resultado. Hugo es el único que tiene más de tres caracteres y menos de cinco. Y aquí si te fijas, ya puse que me fuera hacer el `foreach` sobre el `result2`. Esto de aquí es lo mismo que esto de acá arriba. Y dependiendo a ti, que te haga más fácil escribirlo con funciones encadenadas o con las expresiones o lenguaje de consulta de expresiones de LINQ. Las dos son equivalentes. Al final, está esta expresión de consulta se transforma en esto en el compilador.

Espero que te haya gustado este curso, hayas aprendido algo. Y si es así, bueno, puedes dejar un pulgar arriba. Para ti es gratis, ahí me apoyas bastante con eso. Si te gusta mi contenido, dale al botón suscribir. Y si quieres adquirir el curso de programación backend en C#.NET, bueno, pues ya está el enlace en el primer comentario.

[Música]

Adiós.

[Música]

Ah.