<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Brandon Ventura</title>
    <description>The latest articles on Forem by Brandon Ventura (@brventurau).</description>
    <link>https://forem.com/brventurau</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1373210%2F0a687a96-8030-4c93-8a2d-a769c432d2c0.jpg</url>
      <title>Forem: Brandon Ventura</title>
      <link>https://forem.com/brventurau</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brventurau"/>
    <language>en</language>
    <item>
      <title>ApiControllerAttribute en .NET Core</title>
      <dc:creator>Brandon Ventura</dc:creator>
      <pubDate>Sat, 25 Jan 2025 13:41:24 +0000</pubDate>
      <link>https://forem.com/brventurau/apicontrollerattribute-en-net-core-2kb8</link>
      <guid>https://forem.com/brventurau/apicontrollerattribute-en-net-core-2kb8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flskg9rqyxv5kqoeqy90g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flskg9rqyxv5kqoeqy90g.png" alt="Texto contenido en la imagen que dice ASP .NET Core" width="750" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Muchas veces dentro del desarrollo de Web APIs con .NET Core nos encontramos utilizando notaciones, recursos, atributos que vienen disponibles con el entorno y esto lo realizamos de manera prácticamente automática, en general, esto habla muy bien del trabajo por detrás del equipo encargado del mantenimiento de .NET, ya que como desarrolladores nos mantiene aislados de preocupaciones técnicas para enfocarnos en el desarrollo de funcionalidades del negocio.&lt;/p&gt;

&lt;p&gt;Uno de estos pequeños componentes es el atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; que colocamos tan mecánicamente a nuestros controladores de API nada más crearlos, siendo una de las bondades disponibles y que en lo personal aportan tanto a la productividad en el desarrollo de Web APIs y uno de los que más me hacen falta cuando me encuentro dando mantenimiento a aplicaciones construidas sobre .NET Framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Antes de &lt;code&gt;ApiControllerAttribute&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Antes de .NET Core en .NET Framework no disponíamos de la clase o atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt;, en realidad, no existe nada parecido en ASP .NET Framework (aunque podemos escribir filtros de acciones para lograr el mismo objetivo) y es importante no confundir este atributo con la clase &lt;code&gt;ApiController&lt;/code&gt; en .NET Framework ya que esta clase proporciona la funcionalidad básica para procesar solicitudes HTTP a través de un conjunto de métodos y funcionalidades relacionadas con la escritura de controladores de Web API en .NET Framework más que modificar el comportamiento por defecto de estos controladores.&lt;/p&gt;

&lt;p&gt;En ASP .NET Framework tenemos disponibles las clases &lt;code&gt;Controller&lt;/code&gt; y &lt;code&gt;ApiController&lt;/code&gt; cada una utilizada según el tipo de proyecto, &lt;code&gt;Controller&lt;/code&gt; para controladores que principalmente realizan tratamiento de datos para el renderizado de vistas y &lt;code&gt;ApiController&lt;/code&gt; para tratamiento de datos como servicios web o Web APIs.&lt;/p&gt;

&lt;p&gt;Sin embargo, en .NET Core desde su primera versión vino con una sola clase unificada para los controladores, esta es la clase &lt;code&gt;Controller&lt;/code&gt; que combina las clases &lt;code&gt;Controller&lt;/code&gt;, &lt;code&gt;ApiController&lt;/code&gt; y &lt;code&gt;AsyncController&lt;/code&gt; de ASP .NET Framework MVC y Web API. Además de la clase &lt;code&gt;Controller&lt;/code&gt; .NET Core añade la clase &lt;code&gt;ControllerBase&lt;/code&gt; de la cual hereda &lt;code&gt;Controller&lt;/code&gt;. &lt;code&gt;ControllerBase&lt;/code&gt; provee la funcionalidad básica para manejo de solicitudes HTTP pero no incluye el soporte de vistas y todo lo relacionado con estas que sí tiene la clase &lt;code&gt;Controller&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si lo ponemos sobre el papel en .NET Core, la clase &lt;code&gt;ControllerBase&lt;/code&gt; sería lo mismo que &lt;code&gt;ApiController&lt;/code&gt;  y &lt;code&gt;Controller&lt;/code&gt; lo mismo que la clase &lt;code&gt;Controller&lt;/code&gt; de .NET Framework, salvando las grandes diferencias que hay.&lt;/p&gt;

&lt;p&gt;La clase &lt;code&gt;ApiController&lt;/code&gt; estuvo disponible en .NET Core hasta la versión 2.2 y además, por si te da curiosidad, sí, en ASP .NET Framework existe una clase llamada &lt;code&gt;ControllerBase&lt;/code&gt; que contiene lo mínimo necesario para todos los controladores de vistas, pero no es una clase utilizada para crear controladores que respondan a solicitudes HTTP directamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entonces, ¿Para que sirve el &lt;code&gt;ApiControllerAttribute&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Agregar la anotación o atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; a los controladores, nos brinda un conjunto de características y comportamientos que ayudan a mejorar el trabajo de los desarrolladores dentro de estos, reduciendo la cantidad de código innecesario o repetitivo dentro del controlador y sus acciones.&lt;/p&gt;

&lt;p&gt;Agregar el atributo nos brinda la capacidad de: enrutamiento, validación automática/implícita de modelos, parameter binding mediante inferencia, entre otras cosas.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo se utiliza?
&lt;/h3&gt;

&lt;p&gt;Tenemos tres formas de utilizar el atributo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Controladores individuales.&lt;/li&gt;
&lt;li&gt;Desde una clase base.&lt;/li&gt;
&lt;li&gt;Al ensamblado completo (Assembly).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Controladores individuales
&lt;/h3&gt;

&lt;p&gt;Para agregarlo a nuestros controladores individuales debemos colocarlo sobre la definición de la clase del controlador, esto habilitará las características que dispone el atributo para nuestro controlador.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonasController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Endpoints&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Con una clase base
&lt;/h3&gt;

&lt;p&gt;Debemos crear una clase que disponga del uso del atributo y herede de &lt;code&gt;ControllerBase&lt;/code&gt;, de esta manera podremos heredar nuestra clase base a múltiples subclases y así disponer el atributo a más de un solo controlador sin necesidad de constantemente colocarlo sobre la definición del tipo de nuestro controlador.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Clase base&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppBaseController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Subclase&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonasController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AppBaseController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Endpoints&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A todo el ensamblado
&lt;/h3&gt;

&lt;p&gt;Por último, podemos aplicar el atributo a nivel de ensamblado, lo que lo agregara el atributo a todos los controladores del ensamblado; no se pueden excluir controladores específicos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;assembly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Add services to the container.&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEndpointsApiExplorer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSwaggerGen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Configure the HTTP request pipeline.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDevelopment&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwagger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSwaggerUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpsRedirection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  RouteAttribute
&lt;/h2&gt;

&lt;p&gt;Si agregamos el atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; para decorar nuestros controladores, obligatoriamente debemos utilizar el atributo &lt;code&gt;RouteAttribute&lt;/code&gt; para indicar la ruta a la que responderán las acciones del controlador.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonasController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No podemos dejar que la ruta se defina mediante las rutas convencionales del método &lt;code&gt;UseEndpoints&lt;/code&gt;, &lt;code&gt;UseMvc&lt;/code&gt; o &lt;code&gt;UseMvcWithDefaultRoute&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validación Automática de Modelo
&lt;/h2&gt;

&lt;p&gt;Cuando utilizamos el atributo &lt;code&gt;[ApiController]&lt;/code&gt; todos los errores de validación, tipado y restricciones de nuestros modelos se aplican automáticamente devolviendo una respuesta &lt;code&gt;HTTP 400 Bad Request&lt;/code&gt;; de esta forma la validación es implícita en lugar de explícita, es decir, no necesitamos agregar código que verifique si nuestro modelo es correcto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;CreatePets&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;Pet&lt;/span&gt; &lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Permitiendo eliminar así las siguientes líneas de las acciones de nuestro controlador:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En especial esto es lo que más aporta en cuanto a productividad cuando creamos nuestros controladores, ya que además de evitar repetir estas mismas líneas de código una y otra vez, evitamos que nuestros modelos pasen sin validar en caso que olvidáramos verificar si el &lt;code&gt;ModelState&lt;/code&gt; es valido o no.&lt;/p&gt;

&lt;p&gt;Si nosotros no validamos nuestro modelo explícitamente y tampoco hacemos uso del atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt;ASP .NET Core no nos alertará de que nuestro modelo es inválido o no contiene la información que debería.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10y57vmjc6b3vsvguzm3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10y57vmjc6b3vsvguzm3.png" alt="Respuesta con código 400 ejemplo básico" width="515" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La imagen anterior representa una respuesta de validación utilizando la validación explícita o manual. Si nosotros agregamos el atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; se ve de la siguiente manera:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov6m872od7z0evrmwgag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov6m872od7z0evrmwgag.png" alt="Imagen con código de estado 400 con ValidationProblemDetails" width="671" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este mensaje de error es la respuesta &lt;code&gt;HTTP 400&lt;/code&gt; predeterminada utilizando el comportamiento definido por defecto gracias al &lt;code&gt;ApiControllerAttribute&lt;/code&gt;. El tipo que utiliza es &lt;code&gt;ValidationProblemDetails&lt;/code&gt; en lugar de &lt;code&gt;BadRequestResult&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El tipo &lt;code&gt;ValidationProblemDetails&lt;/code&gt; proporciona un formato que especifica los errores en las respuestas con mucho mayor detalle para humanos y máquinas y además cumple los requisitos establecidos por la &lt;strong&gt;RFC 7807&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por ello, si realizamos validaciones personalizadas en las que tengamos que hacer uso del &lt;code&gt;ModelState&lt;/code&gt; en nuestras acciones, es más conveniente hacer uso del método &lt;code&gt;ValidationProblem(ModelState)&lt;/code&gt; en lugar de &lt;code&gt;BadRequest(ModelState)&lt;/code&gt;, o simplemente &lt;code&gt;ValidationProblem()&lt;/code&gt; ya que usara la propiedad &lt;code&gt;ModelState&lt;/code&gt; del controlador por defecto, de esta forma mantendremos todas nuestras respuestas consistentes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;ValidationProblem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A continuación puedes observar lo mencionado anteriormente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonasController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Utiliza la validación explícita o manual del ModelState retornando un &amp;lt;see cref="BadRequestResult" /&amp;gt;.&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CrearPersona1"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;CrearPersona1&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Persona&lt;/span&gt; &lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Utiliza la validación explícita o manual del ModelState retornando un &amp;lt;see cref="ValidationProblemDetails" /&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CrearPersona2"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;CrearPersona2&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Persona&lt;/span&gt; &lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;ValidationProblem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// es igual a return ValidationProblem(ModelState);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Deja que el atributo &amp;lt;see cref="ApiControllerAttribute" /&amp;gt; se encargue del comportamiento relacionado&lt;/span&gt;
    &lt;span class="c1"&gt;/// a la validación del ModelState.&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CrearPersona3"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt; &lt;span class="nf"&gt;CrearPersona3&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Persona&lt;/span&gt; &lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Invalid Model Response Customization&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Si la respuesta estándar por defecto de los errores de validación aplicada mediante &lt;code&gt;ValidationProblemDetails&lt;/code&gt; no cumple con nuestras necesidades o incluso queremos personalizarla, también lo podemos hacer.&lt;/p&gt;

&lt;p&gt;Para ello debemos modificar el “comportamiento” de devolución de estas respuestas en nuestra API. ASP .NET Core provee una configuración especial para modificar el comportamiento de diversos aspectos de nuestra API, esto a partir del método &lt;code&gt;ConfigureApiBehaviorOptions()&lt;/code&gt; sobre &lt;code&gt;AddControllers()&lt;/code&gt; en los servicios de nuestra API.&lt;/p&gt;

&lt;p&gt;En las opciones de configuración del método &lt;code&gt;ConfigureApiBehaviorOptions()&lt;/code&gt; tendremos disponible la propiedad &lt;code&gt;InvalidModelStateResponseFactory&lt;/code&gt; que recibe un delegado o callback mediante el cual podremos indicar nuestra respuesta personalizada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureApiBehaviorOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvalidModelStateResponseFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;prop1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Propiedad 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;prop2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Propiedad 2"&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BadRequestObjectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;InvalidModelStateResponseFactory&lt;/code&gt; recibe de entrada un &lt;code&gt;ActionContext&lt;/code&gt; que contiene la información del contexto para la ejecución de la acción que ha sido parte de esa solicitud HTTP, además, este delegado devuelve o debe devolver un &lt;code&gt;IActionResult&lt;/code&gt; que determinara nuestra respuesta, en este caso un &lt;code&gt;BadRequestObjectResult&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flecj01maxmt89uh77djx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flecj01maxmt89uh77djx.png" alt="Ejemplo de InvalidModelStateResponseFactory básico" width="413" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo anterior es un ejemplo básico, pero podemos personalizarlo a nuestro gusto, por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureApiBehaviorOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvalidModelStateResponseFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;httpMethod&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ActionDescriptor&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ControllerActionDescriptor&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="n"&gt;ControllerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ActionDescriptor&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ControllerActionDescriptor&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="n"&gt;ActionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelState&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToDictionary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorMessage&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BadRequestObjectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir del contexto &lt;code&gt;ActionContext&lt;/code&gt; podemos obtener información referente al contexto HTTP de la solicitud, datos sobre el controlador y la acción ejecutada, el método de acción, la ruta y el &lt;code&gt;ModelState&lt;/code&gt; para realizar el mapeo de la información de nuestro modelo, en este caso, la respuesta para un modelo inválido.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4augp8rm1tnlukzzbo95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4augp8rm1tnlukzzbo95.png" alt="Ejemplo de InvalidModelStateResponseFactory completo" width="672" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Al crear un nuevo delegado estamos sobrescribiendo la configuración por defecto de la propiedad &lt;code&gt;InvalidModelStateResponseFactory&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por defecto, utiliza la clase &lt;code&gt;ProblemDetailsFactory&lt;/code&gt; que prácticamente devuelve una respuesta a partir de una instancia de &lt;code&gt;ValidationProblemDetails&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Además, podemos incluir servicios dentro de este delegado, gracias a que &lt;code&gt;ActionContext&lt;/code&gt; contiene el &lt;code&gt;HttpContext&lt;/code&gt; de la solicitud, podemos solicitar los servicios disponibles dentro del contenedor de servicios de la solicitud, por ejemplo, podemos obtener el servicio de registro/trace/logs para guardar información referente a los errores de validación del modelo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestServices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hola desde modelo inválido!."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;También podemos desactivar estas respuestas automáticas completamente si configuramos la propiedad &lt;code&gt;SuppressModelStateInvalidFilter&lt;/code&gt; a &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureApiBehaviorOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SuppressModelStateInvalidFilter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Source Binding Inference Rules&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Cuando nosotros aplicamos el atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; sobre nuestros controladores, esté provee una característica que permite inferir/determinar el origen/fuente de donde provienen algunos parámetros de acción sin la necesidad que nosotros como desarrolladores debamos colocar explícitamente el origen de los datos utilizando los atributos de enlace de datos, como puede ser &lt;code&gt;FromBody&lt;/code&gt;, &lt;code&gt;FromForm&lt;/code&gt;, &lt;code&gt;FromQuery&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ApiControllerAttribute&lt;/code&gt; aplica las siguientes reglas de inferencia:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Binding Attribute&lt;/th&gt;
&lt;th&gt;Regla de Inferencia&lt;/th&gt;
&lt;th&gt;Origen de enlace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[FromBody]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inferido para cualquier tipo complejo, por ejemplo, las clases que nosotros mismos creamos. Si una acción hace referencia por inferencia o explícitamente a más de un parámetro desde el cuerpo de la solicitud, producirá una excepción.&lt;/td&gt;
&lt;td&gt;Cuerpo de la solicitud.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[FromForm]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inferido a partir de cualquier parámetro del tipo &lt;code&gt;IFormFile&lt;/code&gt; o &lt;code&gt;IFormFileCollection&lt;/code&gt;, por ejemplo, cuando hacemos envío de archivos como imágenes o documentos. Si el parámetro está contenido dentro de un tipo complejo definido por el usuario, no se realiza la inferencia, hay que indicar explícitamente la fuente de información.&lt;/td&gt;
&lt;td&gt;Datos del formulario en el cuerpo de la solicitud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[FromRoute]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inferido para cualquier parámetro de acción donde el nombre de la variable de parámetro coincida con un parámetro de ruta, es decir, aquellos que colocamos en la plantilla de ruta del endpoint o controlador.&lt;/td&gt;
&lt;td&gt;A través de parámetros de consulta en la URI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[FromQuery]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inferido para cualquier otro parámetro de acción.&lt;/td&gt;
&lt;td&gt;Desde la ruta de la solicitud actual, es decir, parte de la URI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[FromHeader]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No hay una regla de inferencia para el enlace por encabezado.&lt;/td&gt;
&lt;td&gt;Encabezado de la solicitud.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[FromServices]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parámetros de tipo complejo que se encuentran registrados en el contenedor de dependencias.&lt;/td&gt;
&lt;td&gt;Servicio de solicitud extraído del contenedor de dependencias&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Si nosotros no hacemos uso del atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; y además no colocamos ningún atributo de enlace de modelo para la fuente, podemos tener comportamientos inesperados, como por ejemplo, un objeto complejo se espere a través de &lt;code&gt;QueryString&lt;/code&gt; en lugar del &lt;code&gt;Body&lt;/code&gt; o &lt;code&gt;Payload&lt;/code&gt; de la solicitud.&lt;/p&gt;

&lt;p&gt;Podemos desactivar todas las reglas de inferencia agregando la configuración &lt;code&gt;SuppressInferBindingSourcesForParameters&lt;/code&gt; a &lt;code&gt;true&lt;/code&gt; dentro del comportamiento de nuestra API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureApiBehaviorOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SuppressInferBindingSourcesForParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos deshabilitar la inferencia de servicios para un único parámetro de acción, aplicando el atributo correspondiente al origen del parámetro, en lugar de usar &lt;code&gt;FromServices&lt;/code&gt; (por ejemplo, &lt;code&gt;FromBody&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Por defecto, &lt;code&gt;ApiControllerAttribute&lt;/code&gt; aplica la inferencia para los parámetros de tipo &lt;code&gt;IFormFile&lt;/code&gt; y &lt;code&gt;IFormFileCollection&lt;/code&gt;, el tipo de contenido de la solicitud &lt;code&gt;multipart/form-data&lt;/code&gt; se infiere para estos dos tipos, de tal forma que agrega por defecto una restricción de acción donde los datos deben ser enviados con el tipo de contenido &lt;code&gt;multipart/form-data&lt;/code&gt;, de esta manera los parámetros enlazados deben ser consumidos a partir de los datos de formulario (&lt;code&gt;FormData&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Si queremos deshabilitar este comportamiento por defecto podemos cambiar la propiedad &lt;code&gt;SuppressConsumesConstraintForFormFileParameters&lt;/code&gt; a &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureApiBehaviorOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SuppressConsumesConstraintForFormFileParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Client Problem Details
&lt;/h2&gt;

&lt;p&gt;ASP .NET Core realiza una transformación o mapeo a todos los resultados de error del cliente, es decir, cuando una se envía una respuesta con código de estado 400 o superior. Esta transformación por defecto se basa en la clase &lt;code&gt;ProblemDetails&lt;/code&gt; que a su vez se basa en la misma especificación que &lt;code&gt;ValidationProblemDetails&lt;/code&gt;, es decir, la &lt;strong&gt;RFC 7807&lt;/strong&gt; para respuestas de error con mayor detalle, es más, &lt;code&gt;ValidationProblemDetails&lt;/code&gt; hereda de &lt;code&gt;HttpValidationProblemDetails&lt;/code&gt; que a su vez hereda de &lt;code&gt;ProblemDetails&lt;/code&gt;, por lo tanto, están dentro de la misma jerarquía de clases.&lt;/p&gt;

&lt;p&gt;Un código de respuesta &lt;code&gt;404 Not Found&lt;/code&gt; se vería de la siguiente manera por defecto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqs25kid3pt7mgxhg7geh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqs25kid3pt7mgxhg7geh.png" alt="Imagen con código de estado 404 por defecto" width="670" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El método &lt;code&gt;NotFound()&lt;/code&gt; dentro del controlador genera el código de estado &lt;code&gt;HTTP 404&lt;/code&gt;, donde el cuerpo será un &lt;code&gt;ProblemDetails&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si queremos deshabilitar la respuesta por defecto de &lt;code&gt;ProblemDetails&lt;/code&gt; de forma local, es decir, para un solo endpoint podemos sobreescribirlo enviando la sobrecarga del parámetro &lt;code&gt;value&lt;/code&gt; que recibe el método &lt;code&gt;NotFound()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"La persona que estas buscando no ha sido encontrada."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La respuesta se vería de la siguiente manera:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjaoccd8rx7trdq2j43e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjaoccd8rx7trdq2j43e.png" alt="Imagen con código de estado 404 pasando un valor" width="543" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero si queremos deshabilitar la respuesta de &lt;code&gt;ProblemDetails&lt;/code&gt; para todos los códigos de estado de error, podemos cambiar el valor a true de la propiedad &lt;code&gt;SuppressMapClientErrors&lt;/code&gt; dentro de las opciones de comportamiento del API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureApiBehaviorOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SuppressMapClientErrors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con esto, al ocurrir un error y devolverse un código de estado de error del cliente no tendremos un cuerpo de respuesta por defecto, ya que hemos eliminado el mapeo de errores del cliente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0usx03434tid1ql2qmc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0usx03434tid1ql2qmc0.png" alt="Imagen con código de estado 404 con SuppressMapClientErrors en true" width="705" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SuppressMapClientErrors&lt;/code&gt; por defecto es &lt;code&gt;false&lt;/code&gt;, lo que hará que exista el mapeo, esto a su vez, agrega un filtro de resultado implícitamente a las acciones del controlador que transforman &lt;code&gt;IClientErrorActionResult&lt;/code&gt; a una instancia de &lt;code&gt;ProblemDetails&lt;/code&gt; que a su vez es devuelta como un &lt;code&gt;ObjectResult&lt;/code&gt; que en su propiedad &lt;code&gt;Value&lt;/code&gt; contiene una instancia de &lt;code&gt;ProblemDetails&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para personalizar la salida del filtro (por ejemplo, para devolver un tipo de error diferente), podemos registrar una implementación personalizada de &lt;code&gt;IClientErrorFactory&lt;/code&gt; en la colección de servicios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppClientErrorFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppClientErrorFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IClientErrorFactory&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppClientErrorFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;GetClientError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActionContext&lt;/span&gt; &lt;span class="n"&gt;actionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IClientErrorActionResult&lt;/span&gt; &lt;span class="n"&gt;clientError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogWarning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error del cliente."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ObjectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ClientErrorFactory personalizado."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clientError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podemos ver es una clase que simplemente implementa la interfaz &lt;code&gt;IClientErrorFactory&lt;/code&gt;. El método &lt;code&gt;GetClientError&lt;/code&gt; recibe el &lt;code&gt;ActionContext&lt;/code&gt; que ya vimos anteriormente y además una instancia de &lt;code&gt;IClientErrorActionResult&lt;/code&gt; de la cual podemos conocer el código de estado de la respuesta o procesar el resultado para modificarlo. En este caso simplemente se mapea a un &lt;code&gt;ObjectResult&lt;/code&gt; y se utiliza el servicio de logs para registrar algo que sea de nuestro interés. &lt;/p&gt;

&lt;p&gt;En esta clase podemos inyectar cualquier servicio que necesitemos ya que va a ser parte de nuestro contenedor de dependencias, por lo tanto debemos registrarlo como servicio &lt;code&gt;Singleton&lt;/code&gt; en nuestro contenedor para reemplazar la implementación por defecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IClientErrorFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppClientErrorFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8dixp675wmp7c76d41v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8dixp675wmp7c76d41v.png" alt="Respuesta con código de estado 404 de IClientErrorFactory" width="437" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ten en cuenta que si &lt;code&gt;SuppressMapClientErrors&lt;/code&gt; es &lt;code&gt;true&lt;/code&gt;, el &lt;code&gt;IClientErrorFactory&lt;/code&gt; personalizado no será utilizado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;De esta manera hemos aprendido para qué sirve el atributo &lt;code&gt;ApiControllerAttribute&lt;/code&gt; y como agregarlo a nuestros controladores de recursos para aplicar características y comportamientos predefinidos en ASP .NET Core. Además, hemos aplicado distintas configuraciones que permiten personalizar este comportamiento por defecto, como lo son la respuesta de validación de estado del modelo, códigos de error del cliente, restricciones sobre tipos de archivos, inferencia de tipos y más.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código fuente
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials" rel="noopener noreferrer"&gt;Repositorio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials/tree/main/src/BlogPostTutorials.ApiCtlrAttr/BlogPostTutorials.ApiCtlrAttr.Api/BlogPostTutorials.ApiCtlrAttr.Api" rel="noopener noreferrer"&gt;Archivo fuente&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recursos adicionales
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://code-maze.com/apicontroller-attribute-in-asp-net-core-web-api/" rel="noopener noreferrer"&gt;https://code-maze.com/apicontroller-attribute-in-asp-net-core-web-api/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/es-mx/aspnet/core/web-api/?view=aspnetcore-7.0#apicontroller-attribute" rel="noopener noreferrer"&gt;https://learn.microsoft.com/es-mx/aspnet/core/web-api/?view=aspnetcore-7.0#apicontroller-attribute&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-9.0" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-9.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Common Language Runtime (CLR) e Intermediate Language (IL)</title>
      <dc:creator>Brandon Ventura</dc:creator>
      <pubDate>Sat, 02 Nov 2024 19:59:21 +0000</pubDate>
      <link>https://forem.com/brventurau/common-language-runtime-clr-y-intermediate-language-il-50kj</link>
      <guid>https://forem.com/brventurau/common-language-runtime-clr-y-intermediate-language-il-50kj</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vfrzof71bpjp2vzvmcn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9vfrzof71bpjp2vzvmcn.jpg" alt="CLR and IL write down on a kind of CPU" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando estamos trabajando con la plataforma de .NET tenemos una gran variedad de opciones en cuanto a lenguajes que podemos utilizar para crear nuestras aplicaciones, entre estos están C#, F# y Visual Basic que son los lenguajes más conocidos de la plataforma, aunque no los únicos, ya que además puedes utilizar, por ejemplo, C++, todo esto de manera interoperable, es decir, que puedes realizar tus programas en cualquiera de estos lenguajes y comunicar entre si partes del mismo escritas en los distintos lenguajes soportados por la plataforma.&lt;/p&gt;

&lt;p&gt;Pero, te preguntaras ¿Cómo es todo esto posible? Es magia… O mas bien es la ingeniería por detrás de la plataforma de .NET que permite realizar programas utilizando diversidad de lenguajes en conjunto gracias a su entorno de ejecución mejor conocido como Common Language Runtime (CLR) y un lenguaje especial al cual se compilan nuestros programas hechos con .NET llamado Intermediate Language (IL).&lt;/p&gt;

&lt;h2&gt;
  
  
  Código Administrado y No Administrado
&lt;/h2&gt;

&lt;p&gt;Antes de comenzar a conocer un poco mas sobre el CLR e IL, debemos conocer los conceptos de código administrado y no administrado, esto es importante de destacar ya que una de ambas es la forma en que se ejecutan nuestras aplicaciones en el sistema al cual han sido destinadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Código administrado
&lt;/h3&gt;

&lt;p&gt;El código administrado o gestionado es como su nombre lo dice, cuando el código de nuestro programa, o mas bien los recursos que este utiliza son administrados por un componente adicional en su ejecución que, esto es, nuestro código ejecutándose bajo la supervisión de un entorno de ejecución o maquina virtual, que en el caso de .NET es el CLR la maquina virtual encargada de supervisar o administrar la ejecución de nuestro código y además gestionar el uso de los recursos que el sistema operativo brinda a nuestros programas, de lo cual se vera un poco mas a detalle cuando hablemos del CLR.&lt;/p&gt;

&lt;p&gt;Esto significa que el código de la aplicación no se ejecuta directamente sobre el sistema operativo del dispositivo, sino que en vez de ello, se apoya de un ambiente de ejecución (runtime engine) para ser ejecutado, encargado de asignar recursos y servicios de soporte como seguridad, administración de la memoria, entre otros.&lt;/p&gt;

&lt;p&gt;Este entorno de ejecución es conocido mas formalmente como maquina virtual de proceso o aplicación abreviado PVM (Process-level Virtual Machine) que se ejecuta como una aplicación cualquiera dentro del sistema y soporta un proceso individual e independiente dentro del sistema operativo permitiendo así que los lenguajes en los que fueron escritos nuestras aplicaciones se comuniquen con el sistema, siendo un intermediario entre el lenguaje y el código maquina.&lt;/p&gt;

&lt;p&gt;Normalmente la PVM se crea cuando el proceso es iniciado y se detiene cuando finaliza el proceso, esto es importante, puesto que algunas optimizaciones que son realizadas solo persisten durante el ciclo de vida de dicho proceso.&lt;/p&gt;

&lt;p&gt;Es importante mencionar el termino de PVM, ya que muchas veces asociamos al termino de maquina virtual solo a aquellas que permiten crear una capa adicional en nuestro sistema operativo para ejecutar sobre este otro sistema operativo virtualizado, esto ultimo se conoce como maquina virtual del sistema (System Virtual Machine) la cual su propósito es ejecutar un sistema operativo completo dentro del sistema operativo de nuestra maquina física o anfitriona.&lt;/p&gt;

&lt;h3&gt;
  
  
  Código no administrado
&lt;/h3&gt;

&lt;p&gt;Es código que se ejecuta directamente en el sistema operativo, es decir, no existe ningún entorno de ejecución o maquina virtual intermedia para ser ejecutado, por lo tanto, es responsabilidad del desarrollador gestionar los recursos a los que acceden sus programas para que estos sean eficientes, aunque tienden a tener mayor rendimiento que aquellos con código administrado ya que esta capa intermedia no existe y por lo tanto el proceso de interpretar, compilar o transformar el código a código maquina durante el tiempo de ejecución no existe; los programas escritos en lenguajes que compilan directamente a código máquina como C o C++ serian ejemplos de código no gestionado aunque no significa que no podamos escribir código en C#, por ejemplo, no gestionado.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuál es la Mejor Opción?
&lt;/h3&gt;

&lt;p&gt;Como vemos la diferencia principal entre ambos esta en sobre quien recae la responsabilidad de administrar los recursos del sistema como la memoria o los servicios que se requieran de este, en el caso del código administrado recae sobre el entorno de ejecución o maquina virtual correspondiente mientras que el código no administrado es responsabilidad del desarrollador cuidar estos aspectos.&lt;/p&gt;

&lt;p&gt;La decisión sobre uno u otro dependerá del proyecto en cuestión, y, almenos cuando se desarrolla con .NET la mayoría de los casos de uso están cubiertos, por lo que lo mas común será trabajar con código administrado a través del CLR, permitiendo que la experiencia de desarrollo sea mucho mejor, mejorando la productividad y portabilidad de las aplicaciones.&lt;/p&gt;

&lt;p&gt;Son pocos los casos en que es necesario salir fuera de lo convencional, aunque pueden existir como es el caso de los controladores de dispositivos (device drivers).&lt;/p&gt;

&lt;p&gt;Si por la naturaleza del proyecto es imposible usar código administrado al cien por ciento, puede ser recomendable combinar ambos esquemas: se desarrollan como código no administrado los componentes que así lo requieran, y el resto se implementa como código administrado. &lt;/p&gt;

&lt;p&gt;En cuanto a desempeño de la aplicación se refiere, los mejores resultados se pueden obtener usando código no administrado, sin embargo, con el paso del tiempo los lenguajes, herramientas disponibles y el hardware evolucionan lo que tiene como resultado que en muchas ocasiones las mejoras en rendimiento no serán notables, por lo que utilizar código administrado es prácticamente la opción predeterminada por el beneficio que esto aporta en cuanto a la experiencia de desarrollo que proporciona y la capacidad de ejecutar nuestras aplicaciones o programas en múltiples sistemas y arquitecturas, siempre y cuando el entorno de ejecución lo permita.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2apen3zt82r3sjeqkx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2apen3zt82r3sjeqkx3.png" alt="Managed vs Non Managed Code" width="384" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Language Runtime (CLR)
&lt;/h2&gt;

&lt;p&gt;Su objetivo es el de proporcionar un entorno de ejecución independiente de la plataforma de hardware y del sistema operativo, que oculte los detalles de la plataforma subyacente y permita que un programa se ejecute siempre de la misma forma sobre cualquier plataforma. Esto es debido a que el código de máquina es específico al dispositivo siendo utilizado y programar a ese nivel requiere un conocimiento sobre el sistema operativo y la máquina. El CLR actúa como una máquina virtual, sirviendo de puente entre los lenguajes de alto nivel disponibles en .NET y el código de máquina que la computadora puede entender.&lt;/p&gt;

&lt;p&gt;Si programamos en C#, el CLR, es a Java la JVM (Java Virtual Machine) salvando las diferencias entre ambas plataformas, siendo el ejemplo más conocido y cercano en lo que respecta, ya que su propósito es interpretar, compilar o traducir un código intermedio entre el lenguaje y código máquina.&lt;/p&gt;

&lt;p&gt;De parte de Microsoft se refieren al CLR como un entorno de ejecución de código administrado (managed runtime environment) donde el cual los programas escritos en cualquiera de los lenguajes de la plataforma como Visual Basic, C# o F# después de ser compilados a Intermediate Language puedan ejecutarse en el CLR. Cuando tú escribes tu código en cualquiera de estos lenguajes estableciendo una versión del entorno a utilizar y lo compilas, lo que realmente estás haciendo es crear información descriptiva sobre el programa que es almacenada en el programa compilado como metadatos, estos metadatos están contenidos en archivos &lt;em&gt;.exe&lt;/em&gt; y/o &lt;em&gt;.dll&lt;/em&gt; más conocidos como ensamblados, los cuales se encontraran en lenguaje intermedio optimizado para su ejecución, toda esta información le dice al CLR el lenguaje en el cual fue escrito el programa, la versión, librerías de clases, referencias y todo aquello que el programa necesitará para su ejecución, lo que se conoce como aplicación autocontenida (self-contained application) teniendo todo lo necesario para su ejecución en cualquier máquina con el entorno de ejecución instalado.&lt;/p&gt;

&lt;p&gt;De esta forma el CLR permite a tus programas que, por ejemplo, un objeto instanciado a partir de una clase escrita en un lenguaje pueda llamar al método de otra clase escrita en otro lenguaje.&lt;/p&gt;

&lt;h3&gt;
  
  
  Funciones del CLR
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Administración de memoria a través del Garbage Collector.&lt;/li&gt;
&lt;li&gt;Manejo de excepciones.&lt;/li&gt;
&lt;li&gt;Seguridad de tipos.&lt;/li&gt;
&lt;li&gt;Seguridad entre procesos.&lt;/li&gt;
&lt;li&gt;Administración del código en ejecución.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Componentes del CLR
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Compilador JIT (Just-In-Time Compilation).&lt;/li&gt;
&lt;li&gt;Class loader.&lt;/li&gt;
&lt;li&gt;Thread pool.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq1nz2inc3l3it87gm87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq1nz2inc3l3it87gm87.png" alt="Flow of project compilation on .NET" width="449" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intermediate Language (IL)
&lt;/h2&gt;

&lt;p&gt;También conocido como Microsoft Intermediate Language (MSIL durante la beta de los lenguajes de .NET) o Common Intermediate Language (CIL) es el código generado a partir del proceso de compilación de nuestro programa escrito en el lenguaje de nuestra elección en la plataforma sin importar cual sea este.&lt;/p&gt;

&lt;p&gt;El lenguaje intermedio es código que tiene un menor nivel de abstracción que los lenguajes como C# o F# (lenguajes de alto nivel) lo que lo hace un poco mas difícil de escribir, leer y manejar para los desarrolladores, pero es de mas alto nivel que el código máquina propiamente.&lt;/p&gt;

&lt;p&gt;El lenguaje intermedio trabaja por medio de instrucciones que indican como posicionar o localizar cada uno de los elementos de nuestro programa manipulando así el stack o la pila de ejecución a través de estas instrucciones que indican la operación a realizar. Las instrucciones que componen un programa escrito en lenguaje intermedio son llamadas opcodes (abreviado de operation codes), estas instrucciones se encuentran en los metadatos generados al momento de compilar nuestro programa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4wss7h4mv6v8qo4fqdeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4wss7h4mv6v8qo4fqdeo.png" alt="IL opcodes example" width="300" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo que Microsoft busca a través del lenguaje intermedio es que tengamos la libertad de seleccionar cualquier lenguaje soportado por la plataforma de .NET y programar en este lenguaje sin preocuparnos de como este se ejecutara en cuestión, además de tener la capacidad de utilizar estos lenguajes en conjunto para crear nuestros programas. Esto lo consiguió creando el lenguaje intermedio siguiendo la especificación abierta y estándar técnico conocido como Common Language Infrastructure (CLI) permitiendo así que los programas escritos en cualquier lenguaje sean interoperables entre si y puedan ser ejecutados en distintos tipos de hardware; CLI a su ves incluye el Common Type System (CTS) y Common Language Specification (CLS).&lt;/p&gt;

&lt;p&gt;Algunas implementaciones del CLI son .NET Framework, .NET (o .NET Core) y Mono.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwjqmqwkhiq2ld3hqm7p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwjqmqwkhiq2ld3hqm7p.jpg" alt=".NET Languages, IL, CLR and native code" width="685" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Curiosidades sobre el CLR e IL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ¿La compilación JIT realizada por el CLR se ejecuta por cada método, cada vez que se llama?
&lt;/h3&gt;

&lt;p&gt;El código IL normalmente siempre es pasado por el compilador JIT cada vez que se ejecuta el programa, es decir, se compila en cada ejecución, pero cada pieza de código IL se compila una sola vez cuando es llamado y no vuelve a recompilarse nuevamente una vez ya se ha realizado esta única ocasión, por lo que no hay optimizaciones basadas en el uso o anteriores compilaciones.&lt;/p&gt;

&lt;p&gt;Esto es, conforme los bits de los ensamblados son ejecutados el compilador JIT compila y cachea estos bits en memoria. De esta forma cada bit es solamente compilado una vez antes de su ejecución, luego se utiliza su versión nativa en memoria para su ejecución. Por esta razón la compilación JIT se realizara en cada ejecución del programa ya que como se almacena en memoria el resultado al finalizar el programa es que esta memoria es liberada de nuestro sistema operativo.&lt;/p&gt;

&lt;p&gt;De manera simplificada, esto significa que la compilación ocurre una sola vez por método durante la ejecución del programa en la primera invocación de ese método y cuando el programa se detiene toda la compilación se pierde.&lt;/p&gt;

&lt;p&gt;Es por esto que en muchos tutoriales, blogs o cursos habrás escuchado que mencionan que &lt;em&gt;“al ejecutar la aplicación siempre tardara un poco mas en ejecutarse cuando llamas al método, porque aun no esta en memoria.”&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué ocurre con los genéricos?
&lt;/h3&gt;

&lt;p&gt;Los genéricos en .NET presentan un comportamiento particular respecto a la compilación JIT, ya que el CLR maneja su compilación de manera optimizada dependiendo del tipo con el que se instancien, es decir, si son tipos por valor (value types) o tipos de referencia (reference types) lo cual se explica a continuación:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Cuando un tipo genérico es instanciado con un tipo de valor (por ejemplo, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt;, etc.), el CLR compila una versión específica del método genérico para cada tipo de valor con el que se instancie. Esto se debe a que los tipos de valor en .NET tienen un tamaño y representación diferentes en memoria, por lo que el código generado tiene que ser único para cada tipo de valor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Por ejemplo, la clase genérica &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; la usas con &lt;code&gt;List&amp;lt;int&amp;gt;&lt;/code&gt; y &lt;code&gt;List&amp;lt;double&amp;gt;&lt;/code&gt;, el CLR generará dos compilaciones diferentes, una para &lt;code&gt;int&lt;/code&gt; y otra para &lt;code&gt;double&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto ocurre porque los tipos de valor son almacenados directamente en memoria, y la compilación específica optimiza cómo se manejan esos valores.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Cuando un tipo genérico es instanciado con un tipo de referencia (por ejemplo, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;, o cualquier clase definida por ti), el CLR comparte una única versión compilada para todos los tipos de referencia. Es decir, la compilación JIT se realiza una vez para todos los tipos de referencia, ya que estos tipos son siempre manejados por referencias (punteros o direcciones de memoria), y la representación en memoria es uniforme para todos los tipos de referencia.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Por ejemplo, si usas &lt;code&gt;List&amp;lt;string&amp;gt;&lt;/code&gt; y &lt;code&gt;List&amp;lt;object&amp;gt;&lt;/code&gt;, el CLR compilará una sola versión para los tipos de referencia y la reutilizará para ambos casos.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  ¿Cuándo se usa Reflection también se almacena en memoria el código compilado resultante mediante JIT?
&lt;/h3&gt;

&lt;p&gt;En el caso de utilizar Reflection en .NET para invocar métodos sean genéricos o no, el código sí se compila mediante el JIT y se almacena en memoria: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cuando invocas un método mediante Reflection, el CLR aún tiene que compilar el método desde IL a código máquina usando el JIT. Esto ocurre de la misma manera que si el método hubiera sido invocado directamente en el código.&lt;/li&gt;
&lt;li&gt;Una vez que el método es compilado mediante el JIT, el código resultante se almacena en memoria para reutilizarlo en futuras invocaciones, incluso si el método fue invocado a través de Reflection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El JIT compila el método la primera vez que es invocado y almacena el código nativo en memoria por lo que si vuelves a invocar ese mismo método con Reflection, el CLR reutiliza el código compilado, evitando recompilarlo. &lt;/p&gt;

&lt;p&gt;Prácticamente lo que cambia es como invocas el método, que es estática o directa si llamas al método desde tu código de la forma convencional y dinámica o indirecta que es cuando utilizas Reflection escaneando los metadatos de los tipos para encontrar el método y ejecutarlo; para el CLR da igual la forma en que lo ejecutes, lo único que importa es que estas ejecutándolo y lo compilara a código nativo o maquina, sin embargo, ten en cuenta que usar Reflection afecta el rendimiento pero esto no tiene que ver con el CLR como tal sino mas bien con el uso de la inspección de tipos y el descubrimiento de los mismos en tiempo de ejecución mediante Reflection.&lt;/p&gt;

&lt;p&gt;De esta forma una vez que el método es compilado a código nativo, tanto para invocaciones directas como para invocaciones con Reflection, el código compilado se guarda y se reutiliza. Esto significa que el proceso de compilación en sí no se repite, pero la parte dinámica de la invocación a través de Reflection (búsqueda e invocación) sigue siendo más lenta porque siempre se realizará.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos adicionales
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.geeksforgeeks.org/common-language-runtime-clr-in-c-sharp/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/common-language-runtime-clr-in-c-sharp/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Common_Intermediate_Language" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Common_Intermediate_Language&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.artima.com/articles/clr-design-choices" rel="noopener noreferrer"&gt;https://www.artima.com/articles/clr-design-choices&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://snifftontechnologies.wordpress.com/2014/03/05/what-is-common-language-runtime-in-c/" rel="noopener noreferrer"&gt;https://snifftontechnologies.wordpress.com/2014/03/05/what-is-common-language-runtime-in-c/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Conociendo BenchmarkDotNet</title>
      <dc:creator>Brandon Ventura</dc:creator>
      <pubDate>Sat, 14 Sep 2024 20:32:27 +0000</pubDate>
      <link>https://forem.com/brventurau/conociendo-benchmarkdotnet-kni</link>
      <guid>https://forem.com/brventurau/conociendo-benchmarkdotnet-kni</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdotnet%2FBenchmarkDotNet%2Fec962b0bd6854c991d7a3ebd77037579165acb36%2Fdocs%2Flogo%2Flogo-wide.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdotnet%2FBenchmarkDotNet%2Fec962b0bd6854c991d7a3ebd77037579165acb36%2Fdocs%2Flogo%2Flogo-wide.png" alt="Logo de BenchmarkDotNet, es un caracol con el nombre de la libreria." width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Cómo de eficiente es tu código?, ¿Los cambios que estas haciendo mejoran o empeoran tu aplicación en términos de rendimiento?. Tomar puntos de referencia comparativos (benchmarking) es importante para comprender como tu aplicación mejora o empeora y permitir así evaluar tu código.&lt;/p&gt;

&lt;p&gt;Al momento de hacer pruebas evaluativas piensa en ellas como si fueran pruebas unitarias, no quieres evaluar interacciones complicadas a menos que este sea tu objetivo, por ello, un simple proyecto de consola es útil para poder visualizar las comparaciones del código de tu aplicación.&lt;/p&gt;

&lt;p&gt;En esta ocasión haremos un overview de BenchmarkDotNet y como este nos ayuda a realizar pruebas comparativas o de referencia en nuestro código para tomar decisiones informadas desde el diseño hasta la implementación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeros pasos
&lt;/h2&gt;

&lt;p&gt;Lo primero que debemos realizar es tener una aplicación de consola, esta puedes crearla como cualquier otra aplicación de consola que hayas creado antes, solo ten en cuenta el soporte del paquete (puedes verlo en la pagina oficial &lt;a href="https://benchmarkdotnet.org/articles/overview.html" rel="noopener noreferrer"&gt;BenchmarkDotNet&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtimes:&lt;/strong&gt; Full .NET Framework (4.6+), .NET Core (2.0+), Mono, NativeAOT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS:&lt;/strong&gt; Windows, Linux, MacOS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Languages:&lt;/strong&gt; C#, F#, VB&lt;/li&gt;
&lt;li&gt;BenchmarkDotNet solo funciona con aplicaciones de consola (&lt;a href="https://benchmarkdotnet.org/articles/guides/how-to-run.html" rel="noopener noreferrer"&gt;How to Run&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una vez tengas lista la aplicación procede a instalar el paquete utilizando alguna de las siguientes formas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Package Manager Console:&lt;/strong&gt; &lt;code&gt;Install-Package BenchmarkDotNet -Version 0.14.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.Net CLI:&lt;/strong&gt; &lt;code&gt;dotnet add package BenchmarkDotNet --version 0.14.0&lt;/code&gt;. Recuerda que este comando debes especificar el archivo de proyecto &lt;code&gt;.csproj&lt;/code&gt; al que instalaras el paquete o ubicar tu consola en la ruta donde se encuentre el &lt;code&gt;.csproj&lt;/code&gt; del proyecto al que instalaras el paquete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interfaz del Package Manage:&lt;/strong&gt; Si usas Visual Studio puedes instalar el paquete dando clic derecho sobre tu proyecto en el explorador de soluciones &amp;gt; Administrar Paquetes NuGet (Manage NuGet Packages) &amp;gt; Examinar &amp;gt; Buscar BenchmarkDotNet &amp;gt; Instalar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgvdv951ob56snqvmzog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgvdv951ob56snqvmzog.png" alt="Instalación del paquete de NuGet BenchmarkDotNet." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez listo esto podemos comenzar a escribir nuestro código.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nuestro primer Benchmark
&lt;/h2&gt;

&lt;p&gt;Lo primero que necesitamos es tener código que evaluar, en este caso haremos una simple concatenación de cadenas de texto, para ello creamos la siguiente clase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BenchmarkDemo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ConcatenacionSimple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta clase contiene un método llamado &lt;code&gt;ConcatenacionSimple&lt;/code&gt; que ejecuta un ciclo &lt;code&gt;for&lt;/code&gt; 100 veces y concatena cada numero, aunque esto no es lo primordial, podría ser cualquier código que tu quieras comparar, lo importante a notar es el atributo &lt;code&gt;BenchmarkAttribute&lt;/code&gt; que decora el método &lt;code&gt;[Benchmark]&lt;/code&gt;, este atributo permite marcar un método como método a comparar dentro de la clase, ahora solo necesitamos ejecutar nuestro benchmark, para ello escribimos el siguiente código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BenchmarkRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BenchmarkDemo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si utilizamos TLS (Top-Level Statements) nuestra clase Program.cs se veria de la siguiente forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;BenchmarkDotNet.Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;BenchmarkDotNet.Running&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BenchmarkRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BenchmarkDemo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BenchmarkDemo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ConcatenacionSimple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto suponiendo que nuestra clase &lt;code&gt;BenchmarkDemo&lt;/code&gt; este dentro del mismo archivo pero puede vivir en cualquier parte de nuestra solución (ensamblado, namespace, etc). Si no utilizamos TLS entonces tendríamos la estructura convencional de nuestra clase &lt;code&gt;Program&lt;/code&gt; y dentro del método &lt;code&gt;Main&lt;/code&gt; escribiríamos el runner de nuestro benchmark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BenchmarkRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BenchmarkDemo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez listo esto podemos ejecutar nuestro código, sin embargo, el código debe de ser compilado en modo &lt;code&gt;Release&lt;/code&gt;, esto es porque el modo &lt;code&gt;Debug&lt;/code&gt; es una compilación que no esta totalmente optimizado para realizar las configuraciones ya que este modo utiliza y reserva algunos recursos adicionales para poder permitir depurar nuestro código durante el desarrollo, lo cual esta muy bien durante el desarrollo pero para comparar de manera eficiente nuestro código es necesario optimizar el uso de los recursos por ende utilizaremos el modo &lt;code&gt;Release&lt;/code&gt;, podemos hacerlo de las siguientes dos formas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;.NET CLI:&lt;/strong&gt; Ejecutamos el comando &lt;code&gt;dotnet run --configuration Release&lt;/code&gt;. Al igual que durante la instalación del paquete recuerda que este comando debes especificar el archivo de proyecto .&lt;code&gt;csproj&lt;/code&gt; al que instalaras el paquete o ubicar tu consola en la ruta donde se encuentre el &lt;code&gt;.csproj&lt;/code&gt; del proyecto al que instalaras el paquete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Studio:&lt;/strong&gt; Modificaremos el modo de ejecución desde el menú de herramientas en el IDE para seleccionar &lt;code&gt;Release&lt;/code&gt; en el selector de Configuraciones de Soluciones. Luego, podemos ejecutar nuestra aplicación de consola.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk8q5a4h325mqq7ce8ix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk8q5a4h325mqq7ce8ix.png" alt="Seleccionando modo Release para la compilación" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cualquiera de las opciones que sigas, ejecutara el proyecto en la configuración adecuada. Siempre que ejecutamos una aplicación o sistema por primera vez existe un costo de levantamiento o arranque inicial  de esta, esto es debido a que todos los servicios, recursos, etc. que necesita la aplicación son “levantados” o inicializados durante este arranque inicial por lo que Benchmark.net lo que hace es ejecutarse unas cuantas veces como “calentamientos” antes de comenzar a tomar las ejecuciones como referencia descartando estas ejecuciones y luego comenzar a tomar los resultados una vez la aplicación ya haya pasado este periodo inicial de ejecución, piensa en ello como cuando tu harás tu rutina de ejercicio en casa, en el gimnasio o cualquier otro lugar y calientas un poco antes de comenzar dicha rutina.&lt;/p&gt;

&lt;p&gt;El resultado te muestra la versión del paquete, el sistema operativo y la actualización de este, el procesador y tarjeta grafica, así como la cantidad de CPUs y procesadores lógicos y físicos y el entorno de ejecución. Esto es importante, porque de esta manera conocemos el entorno y recursos en donde nuestra aplicación o en este caso las pruebas están siendo ejecutadas para tenerlo como referencia o replicar estas pruebas. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foupyr2khvme4s9c7h72s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foupyr2khvme4s9c7h72s.png" alt="Resultados de ejecución para el método ConcatenacionSimple." width="753" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto solo te esta haciendo saber respecto a donde se esta ejecutando esta prueba, pero no será lo mismo si lo ejecutas en otra máquina, sin embargo, en términos generales no te están diciendo el rendimiento general de tu código, solo te dicen que esta ejecutándose en tu maquina y que tan rápido se ejecuta en tu maquina, por lo que, no es tan útil si consideramos el proyecto ejecutándose en producción, pero primeros pasos son primeros pasos y estos son importantes.&lt;/p&gt;

&lt;p&gt;Podemos agregar el atributo &lt;code&gt;[MemoryDiagnoser]&lt;/code&gt; a nuestra clase &lt;code&gt;BenchmarkDemo&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MemoryDiagnoser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BenchmarkDemo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ConcatenacionSimple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;texto&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este atributo permite agregar un diagnosticador para conocer cuanta memoria esta siendo utilizada o alojada por el método así como cada una de las generaciones que son creadas por el &lt;code&gt;Garbage Collector&lt;/code&gt; y las recolecciones que este realiza para las operaciones:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbohcxvt7morqehlzhl8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbohcxvt7morqehlzhl8q.png" alt="Resultados agregando el diagnosticador MemoryDiagnoser." width="721" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De esta forma el benchmark identificara que tan eficiente es un método base en la ejecución del mismo un numero determinado de veces.&lt;/p&gt;

&lt;p&gt;El resultado además nos indica las etiquetas o leyendas del resultado que pueden ser mas interesantes o menos según que tanto te gusten las matemáticas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferxvr94j1dk32ul02k6s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferxvr94j1dk32ul02k6s.png" alt="Significado de legendas en las métricas de resultados." width="800" height="142"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quizá las mas relevantes son la media del tiempo de ejecución (&lt;code&gt;Mean&lt;/code&gt;) la desviación estándar (&lt;code&gt;StdDev&lt;/code&gt;) que nos permite estar seguros de si el tiempo de la media es significativo o si el tiempo de cada ejecución esta alejado de esta y la memoria alojada por ejecución (&lt;code&gt;Allocated&lt;/code&gt;)  nos dice cuanta memoria es alojada por llamada del método, en este caso, seria todo lo que almacenamos en nuestras variables.&lt;/p&gt;

&lt;p&gt;Respecto a la columna &lt;code&gt;Gen0&lt;/code&gt; tiene que ver con el funcionamiento interno del &lt;code&gt;Garbage Collector&lt;/code&gt; mas que con una simple métrica de BenchmarkDotNet. &lt;code&gt;Gen0&lt;/code&gt; es el &lt;code&gt;GC&lt;/code&gt; diciendo &lt;em&gt;“me ejecutare y me fijare en de las cosas que no son mas necesarias”&lt;/em&gt; luego de marcar todo aquello que no es necesario marca además los recursos que no puede eliminar porque están siendo utilizadas, de esta forma limpia la memoria de lo que ya no es útil y lo que sigue siendo útil lo marca o lo pasa a Gen1, lo que significa que sobrevivió una limpieza, la limpieza de &lt;code&gt;Gen0&lt;/code&gt;, y cada uno de los recursos adicionales que sigan siendo necesarios los seguirá alojando en &lt;code&gt;Gen0&lt;/code&gt; nuevamente, y volverá a verificar si hay cosas que no se estén utilizando para eliminar el uso de esos recursos y moverá los restantes a &lt;code&gt;Gen1&lt;/code&gt;, de esta forma hasta que todos se liberen, y hará lo mismo con &lt;code&gt;Gen1&lt;/code&gt; para limpiar la memoria liberando los recursos de todo aquello que ya no sea necesario marcado como &lt;code&gt;Gen1&lt;/code&gt; y todo lo que no pueda eliminar se ira a &lt;code&gt;Gen2&lt;/code&gt; y lo enviara ahí, y hará esto una y otra vez. Esto solo es una visión general de manera simplificada de como funciona el &lt;code&gt;Garbage Collector (GC)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarking comparativo
&lt;/h2&gt;

&lt;p&gt;Como ya vimos anteriormente podemos extraer distintas métricas sobre la eficiencia y rendimiento en ejecución de nuestro código con información adicional que nos permite comprender lo que hace la herramienta a través de un vistazo a una ejecución simplificada.&lt;/p&gt;

&lt;p&gt;Ahora bien, el benchmarking no es solo sobre ver que tan rápido se ejecuta tu código, es útil cuando ejecutas código y empiezas a realizar comparaciones, si bien pueden estarse ejecutando en tu maquina, un código que utilizando el mismo entorno y con los mismos recursos tiene peor rendimiento, es altamente probable que vaya a suceder lo mismo en un entorno productivo. Aun así, estas pruebas puedes enviarlas a un entorno similar a producción y podrías utilizar los resultados como un buen punto de entrada para describir fenómenos relacionados al rendimiento en determinada pieza de código.&lt;/p&gt;

&lt;p&gt;Hasta el momento hemos obtenido información pero esta es información sin contexto por lo tanto lo siguiente es, como dar contexto a nuestras comparaciones, ya que si este es un método bien escrito o no, no nos lo puede decir por su cuenta.&lt;/p&gt;

&lt;p&gt;No podemos saber si un método es bueno o malo por si solo, no importa lo que obtengamos, para determinar si un método es bueno o no depende de los requerimientos no funcionales (atributos de calidad) establecidos para ese caso de uso o incluso nuestra aplicación y además &lt;strong&gt;otro método adicional que nos permita compararlos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para lograr este objetivo agregaremos el siguiente método a nuestra clase &lt;code&gt;BenchmarkDemo&lt;/code&gt; y ejecutaremos la aplicación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ConcatenacionConStringBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauxlx0eabn6og4sy2oti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauxlx0eabn6og4sy2oti.png" alt="Resultado comparación método ConcatenacionSimple con ConcatenacionConStringBuilder," width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando visualizamos las cosas por si solas, si, nos da información, obtenemos una premisa de lo que nuestro método puede estar utilizando en términos de recursos, pero esta información es vacía, sin embargo, al comparar un mismo proceso con distintas formas de hacerlo, podemos obtener una imagen completa del rendimiento y ejecución de estos, con esto podemos saber si es eficiente o no y si cumple o no con los atributos de calidad establecidos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Linea base de ejecución
&lt;/h3&gt;

&lt;p&gt;Podemos realizar comparaciones entre métodos tomando como elemento de referencia o linea base uno de los métodos agregando la propiedad &lt;code&gt;Baseline&lt;/code&gt; con valor &lt;code&gt;true&lt;/code&gt; al atributo Benchmark: &lt;code&gt;[Benchmark(Baseline = true)]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Esto nos permite conocer el método sobre el cual vamos a comparar las métricas obtenidas de los otros métodos. La forma normal de hacer las cosas es el método marcado con esta propiedad en el atributo, comparando así las ejecuciones de los otros métodos con este, de ahí el nombre de linea base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzw70og6uoijobuh8caz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzw70og6uoijobuh8caz.png" alt="Incorporando atributo Baseline al método ConcatenacionSimple." width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El ratio o proporción de &lt;code&gt;1.00&lt;/code&gt; es el método considerado o marcado con &lt;code&gt;Baseline&lt;/code&gt; a &lt;code&gt;true&lt;/code&gt;, determinando así en los demás métodos el rendimiento proporcional a esto que este tiene, es decir, si es menos a &lt;code&gt;1.00&lt;/code&gt; es mejor, y la mejora es de &lt;code&gt;1.00&lt;/code&gt; menos el ratio del método en cuestión, por ejemplo, &lt;code&gt;1.00&lt;/code&gt; menos &lt;code&gt;0.27&lt;/code&gt; da &lt;code&gt;0.73&lt;/code&gt;, lo que significa que es &lt;code&gt;73%&lt;/code&gt; mas eficiente en términos de tiempo, etc. Cualquier cosa menor que &lt;code&gt;1.00&lt;/code&gt; es mejor, y si es mayor a &lt;code&gt;1.00&lt;/code&gt; entonces es peor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks entre distintas versiones de .NET
&lt;/h2&gt;

&lt;p&gt;BenchmarkDotNet no solo nos permite comparar ejecución de métodos utilizando un solo entorno, pero además nos permite ejecutar estos métodos y compararlos entre versiones de .NET sin necesidad de crear una nueva aplicación. &lt;/p&gt;

&lt;p&gt;Para lograr esto utilizamos el atributo &lt;code&gt;SimpleJobAttribute&lt;/code&gt; sobre la definición de nuestra clase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;SimpleJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RuntimeMoniker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Net48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;SimpleJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RuntimeMoniker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Net80&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MemoryDiagnoser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BenchmarkDemo&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;RuntimeMoniker&lt;/code&gt; contiene diversos miembros que permiten indicar la versión de .NET que vamos a utilizar; &lt;code&gt;RuntimeMoniker.Net48&lt;/code&gt; se refiere a la versión de .NET Framework 4.8.0 y &lt;code&gt;RuntimeMoniker.Net80&lt;/code&gt; a .NET (.NET Core) 8.0, el argumento&lt;code&gt;baseline: true&lt;/code&gt; hace referencia a que la linea base o con la cual se va a comparar las ejecuciones entre frameworks es con .NET Framework 4.8.0.&lt;/p&gt;

&lt;p&gt;Antes de ejecutar nuestra aplicación de consola para comparar entre versiones de .NET tenemos que realizar lo siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tener instaladas cada una de las versiones de .NET que vayamos a comparar, es decir, en el caso del ejemplo, debemos tener instalado .NET Framework 4.8.0 y .NET 8.0 (.NET Core 8.0) .&lt;/li&gt;
&lt;li&gt;Modificar el proyecto, en mi caso estoy compilando a .NET 8.0 no para .NET Framework 4.8.0 para ello podemos dar &lt;strong&gt;doble clic sobre el proyecto en Visual Studio o Clic Derecho &amp;gt; Editar Archivo del proyecto&lt;/strong&gt;, esto abrirá el archivo &lt;code&gt;.csproj&lt;/code&gt; del proyecto para editarlo, en caso que no uses Visual Studio solo busca dicho archivo en los archivos de la solución.&lt;/li&gt;
&lt;li&gt;Cambiaremos la etiqueta que diga &lt;code&gt;&amp;lt;TargetFramework&amp;gt;net8.0&amp;lt;/TargetFramework&amp;gt;&lt;/code&gt; a &lt;code&gt;&amp;lt;TargetFrameworks&amp;gt;net8.0;net48&amp;lt;/TargetFrameworks&amp;gt;&lt;/code&gt; (agregando una s) separando por punto y coma cada una de las versiones a las que queramos compilar. Ten en cuenta que el valor puede ser diferente considerando las versiones que estemos utilizando.&lt;/li&gt;
&lt;li&gt;Nos alertara de que necesita recargar algunos proyectos, le damos a recargar y luego vamos al menú &lt;strong&gt;Compilar &amp;gt; Recompilar Solucion (Build &amp;gt; Rebuild Solution)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esto limpiara nuestro proyecto e inicializara y compilara todo de nuevo. Ten en cuenta que tener multiples frameworks como objetivo de compilación puede ocasionar algunos problemas de incompatibilidad entre versiones de paquetes y sintaxis del lenguaje C# que no este en versiones anteriores, por ende, utiliza estas comparativas con mucho cuidado, por ejemplo, los TLS no están disponibles en .NET Framework 4.8 ya que este es compatible con C# 7.3 y los TLS están disponibles a partir de C#9 que vino con .NET 5 significando que, nuestra clase &lt;code&gt;Program&lt;/code&gt; debe regresar a su estructura convencional para poder ejecutar el código del benchmark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BenchmarkRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BenchmarkDemo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En términos generales puedes utilizar la compilación a múltiples versiones si te interesa dar el salto de una versión a otra de .NET Framework o .NET Core, por ejemplo, .NET 6 a .NET 8 ya que este año (2024) .NET 6 dejara de tener soporte en noviembre y quieres comparar si vale la pena hacer el salto a .NET 8 o a .NET 9 (con salida en noviembre de 2024) en términos de rendimiento si mejora o no tu aplicación e incluso si una nueva característica incorporada al lenguaje te permite mejorar el rendimiento de tu aplicación.&lt;/p&gt;

&lt;p&gt;Utiliza con precaución esta posibilida de BenchmarkDotNet aun mas si estas comparando versiones de .NET Framework con versiones de .NET Core, por ejemplo, los usings globales, las advertencias y anotaciones nullable, entre otras características no son compatibles con versiones anteriores del lenguaje. &lt;/p&gt;

&lt;p&gt;Algunas de estas características se deben modificar o suprimir en el archivo &lt;code&gt;.csproj&lt;/code&gt; del proyecto, el mío luce de la siguiente forma antes de los cambios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net8.0&lt;span class="nt"&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ImplicitUsings&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/ImplicitUsings&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"BenchmarkDotNet"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"0.14.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y ya con los cambios necesarios luce de la siguiente forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/span&gt;net8.0;net48&lt;span class="nt"&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ImplicitUsings&amp;gt;&lt;/span&gt;disable&lt;span class="nt"&gt;&amp;lt;/ImplicitUsings&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;disable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"BenchmarkDotNet"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"0.14.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cambiando &lt;code&gt;&amp;lt;ImplicitUsings&amp;gt;enable&amp;lt;/ImplicitUsings&amp;gt;&lt;/code&gt; a &lt;code&gt;&amp;lt;ImplicitUsings&amp;gt;disable&amp;lt;/ImplicitUsings&amp;gt;&lt;/code&gt; para desactivar los &lt;code&gt;using&lt;/code&gt; globales implícitos y &lt;code&gt;&amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;&lt;/code&gt; a &lt;code&gt;&amp;lt;Nullable&amp;gt;disable&amp;lt;/Nullable&amp;gt;&lt;/code&gt; para desactivar las anotaciones de tipos de referencia nulos en tiempo de compilación.&lt;/p&gt;

&lt;p&gt;Si ejecutamos ahora el benchmark será el doble o el triple según la cantidad de frameworks con los que estés evaluando tus métodos y tomara mucho mas tiempo teniendo en consideración cada una de las ejecuciones además el &lt;code&gt;Baseline&lt;/code&gt; ahora será el framework y no el método.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzzk99mrroxk8b0sqlfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzzk99mrroxk8b0sqlfc.png" alt="Listado de benchmarks en múltiples frameworks en ejecución." width="688" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y en los resultados veras las ejecuciones de cada uno de los métodos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn5c3vdrw3ar7cw5xxph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn5c3vdrw3ar7cw5xxph.png" alt="Resultado comparativo de benchmarks en múltiples frameworks en ejecución" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la imagen anterior podemos observar una de las mayores razones para cambiar de .NET Framework a .NET Core, y es, el rendimiento de las aplicaciones en .NET Core es muy superior en términos de velocidad, administración de memoria y CPU. Obviamente existen otras razones como que .NET Core es multiplataforma, entre mas, aunque no es el objetivo principal de BenchmarkDotNet determinar esto.&lt;/p&gt;

&lt;p&gt;Tengamos en cuenta que estamos evaluando el mismo código, los mismos métodos, ningún cambio entre plataforma, es una comparativa fiel de ambos entornos, no solo estamos comparando nuestros métodos entre si, sino que además, estamos comparando su entorno de ejecución, lo cual puede ayudarnos a tomar decisiones de manera informada respecto a nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;Podemos comparar que incluso la versión con &lt;code&gt;StringBuilder&lt;/code&gt; en .NET Framework tiene peor rendimiento que la versión normal en .NET Core.&lt;/p&gt;

&lt;p&gt;De nuevo, no podemos establecer que estas métricas obtenidas van a tener ese rendimiento, eso solo ocurre tomando el hardware como un hecho, es decir, siempre y cuando el hardware sea igual o muy cercano obtendremos métricas similares, lo cual es muy difícil conseguir en un servidor de producción, pero si no es posible probarlo, lo que si es posible determinar es la evidente comparativa en el rendimiento entre métodos o incluso entre versiones de .NET, esto permite orientar no solo la decisión sobre los cambios de nuestro código sino además la toma de decisiones de diseño relacionadas al entorno de ejecución.&lt;/p&gt;

&lt;p&gt;De esta forma podemos tomar decisiones informadas y además establecer la relación económica entre el rendimiento de la aplicación, el uso de esta y los beneficios del negocio. Si bien estamos hablando de micro o nano segundos y solo de unos cuantos kilobytes, debemos tener en cuenta que las aplicaciones no son solo utilizadas por un par de usuarios, pueden ser cientos o miles, y ahí es donde las cosas se notan en realidad.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusión&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Muchas veces realizamos cambios a nuestro código pensando que son cambios beneficiosos a nuestra aplicación, cambios de librerías, refactorización, abstracciones, etc, pero a lo mejor, estamos introduciendo componentes que pueden afectar directa o indirectamente el rendimiento, pero, tomando las métricas adecuadas podemos saber si nuestra implementación  tiene tal valor o es mejor dejar nuestro código tal como esta, o incluso si el intercambio de rendimiento por mejorar la experiencia de de desarrollo es conveniente. &lt;/p&gt;

&lt;p&gt;Obviamente, debemos utilizar esto con mucha precaución porque requiere trabajo adicional que no puede ser realmente justificado, por ello, evita realizar optimizaciones prematuras o incorporar flujos de trabajo que realmente no puede verse su valor en las primeras etapas de desarrollo del sistema, si llegas a identificar algo extraño una vez tu aplicación este en uso, ahí es el momento correcto para actuar.&lt;/p&gt;

&lt;p&gt;Si estas realizando pruebas comparativas y vas a decirle a tu jefe algo respecto a los números obtenidos, recuerda no hacerlo en lenguaje técnico diciendo &lt;em&gt;“Este método reduce el uso de memoria de 4kb a 1kb”&lt;/em&gt;, puedes decir algo como &lt;em&gt;“Realizando algunos cambios en la aplicación se puede reducir el uso de memoria en 4 veces”&lt;/em&gt;, mientras mas destacable sea la mejora mas les puede gustar escucharte, y si puedes demostrar tus resultados en términos económicos, ten por seguro que hasta los jefes de tus jefes les encantara, especialmente si son personas mas del negocio que del área técnica. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Se cuidadoso, porque cuando haces benchmark estas ejecutando tu aplicación, tus métodos muchas veces, asegúrate de estar preparado para ello, por ejemplo, si tienes código que ejecuta operaciones hacia la base de datos, asegúrate de que esta este preparada para manejar múltiples operaciones a la vez y además de no utilizar la base de datos de producción para ello, esto mismo aplica para cualquier sistema externo a nuestra aplicación (una API, por ejemplo), además de disponer de los recursos suficientes en tu equipo. No utilices BenchmarkDotNet como un sistema de pruebas de stress, no es su propósito, utilízalo especialmente para las piezas de lógica de tu aplicación, aquellas que se ejecutan por su cuenta, no lo utilices para código que requiere interacción con la UI o sistemas con interacciones complejas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The goal of benchmarking is to test the performance of all the methods that are frequently used (hot paths) and should be performant. &lt;/em&gt;&lt;em&gt;The focus should be on the most common use cases, not edge cases&lt;/em&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Código fuente&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials" rel="noopener noreferrer"&gt;Repositorio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials/blob/main/src/BlogPostTutorials.CodeBenchmarking/BlogPostTutorials.CodeBenchmarking.Console/Program.cs" rel="noopener noreferrer"&gt;Archivo fuente&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si el proyecto no te compila como parte de toda la solución copia el código del archivo &lt;code&gt;Program.cs&lt;/code&gt; y pégalo en un proyecto aparte de la solución.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Recursos adicionales&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dotnet.microsoft.com/en-us/platform/support/policy" rel="noopener noreferrer"&gt;https://dotnet.microsoft.com/en-us/platform/support/policy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dotnet/BenchmarkDotNet" rel="noopener noreferrer"&gt;https://github.com/dotnet/BenchmarkDotNet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://benchmarkdotnet.org/articles/overview.html" rel="noopener noreferrer"&gt;https://benchmarkdotnet.org/articles/overview.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Constructor Primario en las Clases C#</title>
      <dc:creator>Brandon Ventura</dc:creator>
      <pubDate>Tue, 06 Aug 2024 20:00:39 +0000</pubDate>
      <link>https://forem.com/brventurau/constructor-primario-en-las-clases-514i</link>
      <guid>https://forem.com/brventurau/constructor-primario-en-las-clases-514i</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqpl52dav1qf38jva5or.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqpl52dav1qf38jva5or.png" alt="Constructores primarios y refactorización con C# 8" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un constructor?
&lt;/h2&gt;

&lt;p&gt;Si bien, esto es un término que quizá la mayoría ya conozcamos, es importante definirlo para aquellos que vienen de un lenguaje de programación funcional o que no han tenido mucha cercanía con términos relacionados con la Programación Orientada a Objetos (POO), en este caso, relacionados con las clases y los objetos. &lt;/p&gt;

&lt;p&gt;Para empezar una clase es como la plantilla o plano que nos permite definir que es lo que compone un objeto (su estructura) y aquello que este puede hacer, por ejemplo, un gato tiene un nombre, género, edad, color y puede respirar, comer, correr y dormir. Ahora bien, esto como vemos solo es describir de forma simplificada lo que todos los gatos pueden tener, pero si yo tengo un gato en específico, por ejemplo, el gato Tom, este gato en específico es un objeto, una instancia de la clase Gato, ya que tiene sus propias características o atributos que lo diferencian de otros gatos, como el nombre, género, edad, y color, a esto se le conoce como campos de la clase. Por otra parte, todos los gatos hacen de manera generalizada lo mismo, respiran, comen, corren y duermen, esto se convierte en su comportamiento, lo que en términos de clases y objetos serían los métodos de la clase. Ambas cosas, los campos y los métodos son tratados como los miembros de la clase y definen lo que se conoce como estado (información específica de cada objeto almacenado en los campos) y comportamiento (métodos que utilizan el estado para “hacer algo”). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿No estábamos hablando de constructores?&lt;/strong&gt; Sí, sin embargo, los constructores toman sentido cuando conocemos lo que compone una clase, esto es porque los constructores son una especie de métodos especiales que se utilizan para “construir” nuestros objetos de tal forma que permiten definir todo aquello que nuestro objeto necesita al momento de ser creado, es decir, al momento de crear una instancia de la clase.&lt;/p&gt;

&lt;p&gt;En C# podemos tener diversos tipos de constructores como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constructores por defecto y sin parámetros:&lt;/strong&gt; Es un constructor que no toma ningún parámetro y en el cual sus miembros tendrán el valor por defecto al crear el objeto. En C# todas las clases tienen un constructor por defecto que no recibe parámetros si no creamos ningún otro constructor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructores con parámetros:&lt;/strong&gt; Son constructores que reciben información a través de este para ser asignada a los campos de la clase. Son ideales cuando queremos restringir que los valores que componen el objeto deban ser adicionados al momento de crearlos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructores privados:&lt;/strong&gt; Constructores que simplemente están restringidos utilizando el modificador &lt;code&gt;private&lt;/code&gt;, es decir, impiden que los objetos sean creados desde fuera de la clase. Esto es útil por ejemplo, para controlar la forma en que nuestros objetos se crean desde dentro de la propia clase, creando ciertas restricciones al momento de crearlos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructores estáticos:&lt;/strong&gt; Son constructores especiales que permiten asignar o inicializar datos estáticos en nuestra clase. Al ser estáticos significa que no podemos llamarlos al momento de crear nuestra instancia, sino que, el entorno de ejecución se encarga de hacerlo previamente, asignando así la información antes a la creación de nuestro objeto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructores de copia:&lt;/strong&gt; Es un tipo de constructor que en lugar de recibir los valores que vamos a asignar, recibe una instancia/objeto de la clase como argumento, permitiendo así tomar un objeto existente para extraer su información y crear un nuevo objeto a partir de este, es decir, una copia o clon. En resumen, pretenderíamos hacer esto para así tener dos objetos “iguales” (no necesariamente) para modificar uno sin perder la información que este tenía (esta se encuentra en la copia) y utilizar ambos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructor primario:&lt;/strong&gt; Lo veremos a detalle a continuación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada uno de estos constructores puede tener unos cuantos detalles adicionales que vale la pena revisar, sin embargo, no vamos a definir cada uno de estos, puesto que, el objetivo de la publicación es conocer los constructores primarios, aunque, la lista puede permitirte conocer que cuando hablamos de constructores pueden existir en varios colores y sabores (al menos en C#).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Gato&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Genero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;_cantidadDePatas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor sin parametos.&lt;/span&gt;
    &lt;span class="c1"&gt;// Sí no vamos a definir otro constructor o no lo necesitamos&lt;/span&gt;
    &lt;span class="c1"&gt;// podemos borrarlo.&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Gato&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor con parametros&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Gato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;genero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Genero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor privado&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Gato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor estatico&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;Gato&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_cantidadDePatas&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructor de copia&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Gato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gato&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Genero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Genero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ObtenerInformacionGato&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$"El gato se llama &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tiene &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; años y es color &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; y tiene &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_cantidadDePatas&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; patas."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Los constructores por diseño siempre devuelven una nueva instancia de la clase, esto es importante tenerlo en cuenta, porque es su objetivo y no debemos limitar su comportamiento, si lo hacemos, estaríamos yendo en contra de lo que todos los programadores entienden por constructor de una clase introduciendo inconsistencias en nuestro código, esto es lo que permite, por ejemplo, que los constructores de copia funcionen, ya que aunque nosotros recibimos un objeto en el constructor, este siempre si o si devolverá un nuevo objeto, sea si utilizamos lo que recibimos en el constructor o no, al contrario, en un método, podríamos devolver el mismo objeto que recibimos y no nos daríamos cuenta de que se trata del mismo objeto (hasta que ocurran los errores, claro).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Siempre sera un nuevo gato aunque sea una copia.&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Gato&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gato&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Genero&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Genero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gato&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// No hay seguridad que obtenemos una copia real del gato.&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Gato&lt;/span&gt; &lt;span class="nf"&gt;CopiarGato&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Constructores primarios (primary constructors)
&lt;/h2&gt;

&lt;p&gt;Los constructores primarios son un tipo especial de constructor que se coloca junto a la definición del tipo, es decir, del nombre de la clase. Este tipo especial de constructor fue agregado junto con C# 9 y .NET 5 en el 2020 y se ven de la siguiente forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;PersonaRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aunque con los records no es muy común lo siguiente la sintaxis convencional sería:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;PersonaRecord2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PersonaRecord2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si bien los records son otro tipo de dato distinto a las clases (aunque muy similares) y no vamos a entrar en detalle respecto a ellos en esta publicación, con estos llegaron los constructores primarios, y en C# 12 y .NET 8 ahora pueden ser utilizados con las clases y estructuras (struct).&lt;/p&gt;

&lt;p&gt;Estos constructores no son más que una forma/sintaxis especial disponible en C#  para definir nuestro constructor en la definición del tipo o declaración/nombre de la clase. Su sintaxis es prácticamente la misma que con los records, solo cambiando &lt;code&gt;record&lt;/code&gt; por &lt;code&gt;class&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El equivalente a esto en su forma convencional sería lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Persona2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Persona2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como puedes ver, la sintaxis de constructor primario es mucho más reducida y cómoda en cuanto a experiencia de desarrollo respecta.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Ambas formas son equivalente?
&lt;/h3&gt;

&lt;p&gt;Si y no, en cuanto a records respecta, si lo son, debido a que el compilador se hará cargo de tomar los parámetros del constructor y generar los miembros y propiedades públicas correspondientes para los parámetros del constructor primario. Estas propiedades serán un espejo de los parámetros del constructor (nombre y tipo).&lt;/p&gt;

&lt;p&gt;Con las clases funciona igual, ¿no?, pues no, el compilador no hará lo mismo con cualquier otra cosa que utilice un constructor primario y no sea un &lt;code&gt;record&lt;/code&gt;, es decir, las clases y los structs no tendrán este comportamiento. En resumen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;persona&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Error en tiempo de compilación, los miembros no existen en Persona.&lt;/span&gt;
&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;personaRecord&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonaRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Los miembros son accesibles en el tipo PersonaRecord&lt;/span&gt;
&lt;span class="n"&gt;personaRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;personaRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entonces, ¿Cómo puedo acceder al nombre y edad de mi objeto creado a partir de la clase Persona? Pues, prácticamente agregando las propiedades a mano, de la siguiente forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// o&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Así ya tendríamos acceso nuevamente a los miembros de nuestra clase. Quizá esto te recuerda a algo, y sí, así es como se definían las propiedades antes, teniendo un campo privado el cual manipulábamos o encapsulábamos utilizando un método &lt;code&gt;getter&lt;/code&gt; y otro &lt;code&gt;setter&lt;/code&gt;, o como en este caso utilizando las properties de C#.&lt;/p&gt;

&lt;p&gt;Esta no equivalencia de comportamiento entre records y clases o structs se debe a que los primary constructors en las clases/structs define sus parámetros como “privados”, lo que significa que no son accesibles desde ninguna parte fuera de la propia definición de la clase, por eso debemos crear los getters y setters correspondientes para que estos sean el acceso público al estado de nuestra clase.&lt;br&gt;
Además de esto, los records en términos generales son inmutables por diseño, reforzando esto a través del propio constructor primario que define los miembros automáticamente para evitar suprimir este comportamiento, aunque siempre es posible hacerlo si definimos el &lt;code&gt;record&lt;/code&gt; de manera convencional.&lt;/p&gt;
&lt;h2&gt;
  
  
  Consideraciones importantes
&lt;/h2&gt;

&lt;p&gt;Hasta ahora se ha visto esta nueva sintaxis como una alternativa a la sintaxis convencional donde no parece aportar mucho, y en una comparativa muy superficial con los records parece que estos últimos son mejores, y aunque se han venido describiendo a la par hay muchas diferencias que los separan y no serán mencionadas aquí, solo se han mencionado porque los records son con los que se dio origen a esta nueva forma de definir nuestros constructores y aunque esta característica es similar para ambos, el propósito de las clases difiere del de los records, por lo tanto, hay ciertas implicaciones con el uso de constructores primarios en las clases.&lt;/p&gt;
&lt;h3&gt;
  
  
  Sintaxis
&lt;/h3&gt;

&lt;p&gt;Aunque ya la vimos anteriormente, es bueno destacarla nuevamente y aislada de la comparativa con los records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Alcance, acceso y nombramiento
&lt;/h3&gt;

&lt;p&gt;Lo que vemos en la definición del constructor primario no es más que los parámetros del constructor, es decir, solo es una sintaxis adicional para definir un constructor, sin embargo, puede que te preguntes ¿Cuál es el alcance de estos parámetros? ¿Cuál es su nivel de acceso?, y ¿Cuál es la convención o nomenclatura para nombrarlos?&lt;/p&gt;

&lt;p&gt;Bueno, en realidad son solo parámetros, piensa en ellos como los parámetros del constructor convencional o los de una función o método cualquiera, la única diferencia es que los parámetros del constructor primario tienen un alcance global, es decir, pueden ser accedidos y modificados  como cualquier otro parámetro, pero en este caso desde cualquier parte de la clase, estos no están limitados solo al bloque (de forma local) como en los constructores convencionales o las funciones. &lt;/p&gt;

&lt;p&gt;Por lo tanto, podrías hacer algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Formatear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;nombre&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Modificamos el parametro no la propiedad&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como vemos, estamos modificando el parámetro &lt;code&gt;nombre&lt;/code&gt; asignándole un nuevo valor al ejecutar el método &lt;code&gt;Formatear()&lt;/code&gt;, y dirás, bueno, no pasa nada, ¿no?, total si ya hemos asignado el parámetro a la propiedad &lt;code&gt;Nombre&lt;/code&gt;, veamos lo que sucede con el siguiente código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nombrePersona&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;persona&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Persona&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nombrePersona&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Los nombres son iguales: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;nombrePersona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Formatear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Los nombres son iguales: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;nombrePersona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persona&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí tenemos un nombre asignado a una variable y luego utilizamos esta variable para crear nuestro objeto de &lt;code&gt;Persona&lt;/code&gt;, imprimimos el nombre y comprobamos si los nombres son iguales.&lt;/p&gt;

&lt;p&gt;Luego ejecutamos el método &lt;code&gt;Formatear()&lt;/code&gt; y hacemos lo mismo de nuevo, lo que veremos por consola es lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;John&lt;/span&gt; &lt;span class="n"&gt;Doe&lt;/span&gt;
&lt;span class="n"&gt;Los&lt;/span&gt; &lt;span class="n"&gt;nombres&lt;/span&gt; &lt;span class="n"&gt;son&lt;/span&gt; &lt;span class="n"&gt;iguales&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;JOHN&lt;/span&gt; &lt;span class="n"&gt;DOE&lt;/span&gt;
&lt;span class="n"&gt;Los&lt;/span&gt; &lt;span class="n"&gt;nombres&lt;/span&gt; &lt;span class="n"&gt;son&lt;/span&gt; &lt;span class="n"&gt;iguales&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como ves, el valor ha cambiado, no hemos modificado la propiedad &lt;code&gt;Nombre&lt;/code&gt;, sino el parámetro &lt;code&gt;nombre&lt;/code&gt;, pero como la propiedad accede o devuelve directamente el parámetro, cualquier alteración del parámetro &lt;code&gt;nombre&lt;/code&gt; se vera reflejada dentro de cualquier parte de la clase que acceda a él, porque este es mutable, es decir, puede cambiarse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Respondiendo a las preguntas:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;¿Cuál es el alcance de estos parámetros?&lt;/strong&gt; El alcance es global dentro del tipo o clase, es decir, puede ser accedido desde cualquier parte de la propia clase, como cualquier parámetro lo haría dentro del constructor o función.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;¿Cuál es su nivel de acceso?&lt;/strong&gt; No es &lt;code&gt;public/protected/private/internal&lt;/code&gt;, es solo un parámetro, su nivel de acceso está limitado a la clase, como cualquier parámetro de función que estaría limitado solo a esa función. Por este comportamiento podríamos decir que es privado, puedes verlo de esta forma si te resulta más fácil.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;¿Cuál es la convención o nomenclatura para nombrarlos?&lt;/strong&gt; Al ser parámetros, se nombran como tal, usando la nomenclatura &lt;em&gt;camelCase&lt;/em&gt;, es decir, el nombre inicia en minúscula y cada cambio de palabra con letra mayúscula, nada de &lt;em&gt;PascalCase&lt;/em&gt; ni con guion bajo como los campos privados (&lt;code&gt;~~_nombre~~&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inyección de dependencias
&lt;/h3&gt;

&lt;p&gt;Por lo anteriormente dicho y comprobado, tenemos que tener mucho cuidado con el uso que les daremos a estos parámetros, si por ejemplo vamos a utilizarlos para la inyección de dependencias, porque hasta este momento no existe ningún tipo de restricción que pueda ser aplicada sobre estos para evitar que sean modificados dentro de la clase, por lo que, cualquier sentencia dentro de nuestra clase puede alterar su valor o contenido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServicioFalso&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;RetornaTextoMayuscula&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OtroServicio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ServicioFalso&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ObtenerMensaje&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RetornaTextoMayuscula&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hola Mundo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HacerAlgo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El código anterior expresa de manera muy simplificada una posible inyección de dependencias, como vez, el método &lt;code&gt;ObtenerMensaje()&lt;/code&gt; llama al método &lt;code&gt;RetornaTextoMayuscula()&lt;/code&gt; de la clase inyectada o pasada como parámetro &lt;code&gt;ServicioFalso&lt;/code&gt; y convierte el texto a mayúscula, haciendo lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ServicioFalso&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;otroServicio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OtroServicio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mensaje&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;otroServicio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ObtenerMensaje&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veríamos por consola el texto en mayúscula “HOLA MUNDO”, pero si en cambio, hacemos lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;otroServicio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HacerAlgo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;mensaje&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;otroServicio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ObtenerMensaje&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El programa nos lanzaría una excepción &lt;code&gt;NullReferenceException&lt;/code&gt;, esto es debido a que cuando ejecutamos el método &lt;code&gt;HacerAlgo()&lt;/code&gt;, este asigna el valor del parámetro &lt;code&gt;servicioFalso&lt;/code&gt; a &lt;code&gt;null&lt;/code&gt;, por lo que al llamar nuevamente al método &lt;code&gt;ObtenerMensaje()&lt;/code&gt; que utiliza este parámetro, su valor será &lt;code&gt;null&lt;/code&gt; y se lanzará la excepción.&lt;/p&gt;

&lt;p&gt;Dicho esto, no puedes confiar en el valor que fue pasado como argumento a estos parámetros, a menos que, hayas inicializado campos o propiedades de solo lectura.&lt;/p&gt;

&lt;p&gt;Lo ideal sería utilizar la forma convencional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OtroServicio2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ServicioFalso&lt;/span&gt; &lt;span class="n"&gt;_servicioFalso&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OtroServicio2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ServicioFalso&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ObtenerMensaje&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_servicioFalso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RetornaTextoMayuscula&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hola Mundo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HacerAlgo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Error de compilación, no se puede asignar un valor a un campo de solo lectura, solo durante la inicialización&lt;/span&gt;
        &lt;span class="n"&gt;_servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pero, ¿Si la forma convencional es la correcta, para qué utilizaría un constructor primario para la inyección de dependencias? Y es que es posible encontrar un punto intermedio, donde se utilicen los constructores primarios y apliquen restricciones sobre estos valores de la siguiente forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OtroServicio3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ServicioFalso&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ServicioFalso&lt;/span&gt; &lt;span class="n"&gt;_servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;servicioFalso&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ObtenerMensaje&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_servicioFalso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RetornaTextoMayuscula&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hola Mundo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HacerAlgo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Error de compilación, no se puede asignar un valor a un campo de solo lectura, solo durante la inicialización&lt;/span&gt;
        &lt;span class="n"&gt;_servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Es posible al parametro pero no al campo de solo lectura&lt;/span&gt;
        &lt;span class="n"&gt;servicioFalso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el código anterior utilizamos los parámetros del constructor primario para asignarlos a un campo de solo lectura, de la misma forma en que lo hacemos con un constructor convencional, y dentro de la clase utilizamos este campo de solo lectura para las operaciones que necesitemos y nos olvidamos de lo que sea que haya dentro del parámetro del constructor, de esta forma aseguramos la seguridad del código y además evitamos el código repetitivo del constructor.&lt;/p&gt;

&lt;p&gt;Esta forma sería la ideal de trabajar con los constructores primarios y la inyección de dependencias mientras no exista ningún tipo de atributo o característica dentro de C# que nos permita indicar un comportamiento distinto dentro del constructor primario.&lt;/p&gt;

&lt;p&gt;Para la mayoría de los casos es preferible el uso del constructor convencional en las clases y structs antes que el constructor primario. En el caso de los records, el constructor primario siempre es preferido a menos que vayamos a hacer algo especial con el record.&lt;/p&gt;

&lt;h2&gt;
  
  
  DTOs
&lt;/h2&gt;

&lt;p&gt;Si bien un buen uso para los constructores primarios en las clases puede ser en la definición de DTOs, puede ser buena idea utilizarlos si lo único necesario es mover datos a lo largo de la aplicación que no tengan ningún tipo de restricción y además, por alguna razón quieras mantener esta información mutable, que pueda cambiar en algún momento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonaDto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edad&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aunque, siendo este el caso, en lo personal prefiero el uso de records, ya que estos tienen una sintaxis mucho más simplificada, y además refuerzan el diseño inmutable, haciendo que nuestros datos sean consistentes a lo largo del uso que les demos, además que nos brindan grandes características como la igualdad en los objetos, una mejor lectura en cuanto a logs respecta, entre más:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;PersonaRecordDto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nombre&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Edad&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Con la llegada de los records a partir de C# 9 es indiscutible que estos introdujeron características y comportamientos interesantes al lenguaje, siendo la nueva sintaxis de los constructores primarios algo que llamo mucho la atención, hasta ser incorporados en C# 12 a las clases y los structs, convirtiéndose en una forma mucho más simplificada de crear los constructores y reduciendo el código repetitivo de nuestras clases en cuanto a constructores respecta, sin embargo, el mayor problema de los constructores primarios en las clases y structs es que se comportan distinto a como lo hacen en los records lo que puede ocasionar confusiones y problemas al momento de utilizarlos al no conocer como funcionan en realidad, y aunque  esto puede ser resuelto de múltiples maneras como hemos visto a lo largo de esta publicación siempre es importante estar al tanto de estos detalles y muchos más que puede surgir con las nuevas características del lenguaje y mantener informados a los miembros del equipo en cuanto al uso de estas respecta. &lt;/p&gt;

&lt;p&gt;Algunas veces más es menos y menos es más. Si es más cómodo seguir trabajando de la forma convencional, hazlo, si decides utilizar los constructores primarios ten al tanto a tus compañeros de equipo sobre esa decisión y comparte tu conocimiento con ellos para que su experiencia de desarrollo no se vea frustrada por algún problema de como estos funcionan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como recomendación:&lt;/strong&gt; Utiliza los valores pasados como argumentos a los parámetros de tu constructor primario solo para la inicialización de campos y propiedades, evita utilizarlos, acceder a ellos o modificarlos en cualquier otro lugar, a menos que sea algo trivial y sin restricciones. Piensa en ellos como los parámetros de un constructor convencional, normalmente solo se usan para asignar campos y propiedades, validaciones u operaciones muy sencillas, nada más.&lt;/p&gt;

&lt;p&gt;Además, estos son nombrados como parámetros convencionales y no pueden ser distinguidos de los parámetros utilizados dentro de las funciones/métodos de la clase lo que puede ocasionar problemas, contrario a los campos privados de la clase que por convención (regla no escrita en piedra) se les coloca el guion bajo “_” para diferenciarlos y saber donde encontrarlos. Puede parecer una tontería, pero al momento de hacer code reviews o ver el código de un proyecto que estás trabajando ayuda a aclarar dudas y facilitar la búsqueda de estos. Por cierto, si piensas que puedes nombrar los parámetros del constructor primario con guion bajo (&lt;code&gt;_servicio&lt;/code&gt;) en realidad puedes hacerlo, pero recuerda, son parámetros no campos de la clase, en resumen, si haces algo como &lt;code&gt;this._servicio&lt;/code&gt; para acceder a ellos no funcionara, es un parámetro no un campo o miembro de la clase.&lt;/p&gt;

&lt;p&gt;Está claro que hay beneficios de utilizar los constructores primarios, pero no los sobreutilices o los veas como una regla escrita en piedra. Hasta que no podamos agregar restricciones o anotaciones especiales a estos parámetros, por ejemplo para limitar su mutabilidad (no podemos marcarlos como readonly, init, etc), pueden representar más un problema que una solución si no los utilizas correctamente y con cuidado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código fuente
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials" rel="noopener noreferrer"&gt;Repositorio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials/blob/main/src/BlogPostTutorials.PrimaryConstructor/BlogPostTutorials.PrimaryConstructor.Console/Program.cs" rel="noopener noreferrer"&gt;Archivo fuente&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recursos adicionales
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/y3--fmLLmQA?si=AySAchjj3FdkjPA6" rel="noopener noreferrer"&gt;https://youtu.be/y3--fmLLmQA?si=AySAchjj3FdkjPA6&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://code-maze.com/csharp-constructors/" rel="noopener noreferrer"&gt;https://code-maze.com/csharp-constructors/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Operador Ternario ?: en C#</title>
      <dc:creator>Brandon Ventura</dc:creator>
      <pubDate>Mon, 29 Jul 2024 16:16:20 +0000</pubDate>
      <link>https://forem.com/brventurau/operador-ternario-en-c-2k59</link>
      <guid>https://forem.com/brventurau/operador-ternario-en-c-2k59</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrcylun1av05izzpftee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrcylun1av05izzpftee.png" alt="Elvis Presley con un signo de interrogación en el cabello y dos puntos en los ojos" width="225" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es el operador ternario?
&lt;/h2&gt;

&lt;p&gt;El operador ternario es un operador condicional en C# como en múltiples lenguajes de programación. Si te sirve para recordarlo puedes hacer referencia al nombre de Elvis Operator, aunque este nombre es el nombre del operador de nulos en Kotlin y se aplica de forma distinta, pero a mí me sirve para recordar que debemos usar un signo de interrogación de cierre y dos puntos dentro de su sintaxis.&lt;/p&gt;

&lt;p&gt;El semejante del Elvis Operator en C# es el Null-Coalescing Operator (??), pero este ya es otro tema.&lt;/p&gt;

&lt;p&gt;Retomando, el operador ternario nos ayuda a definir de forma corta y/o reducida la ejecución de ciertas sentencias, asignación de valores y pequeños procesos basados en condiciones; puedes verlo como una alternativa reducida de la sentencia if-else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sintaxis del operador ternario
&lt;/h2&gt;

&lt;p&gt;Este operador siempre debe constar de 3 operandos o elementos  (de ahí su nombre):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Expresión condicional:&lt;/strong&gt; Es la evaluación lógica que esperamos realizar (resultado de true o false).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La primera declaración:&lt;/strong&gt; La expresión, resultado o valor que esperamos obtener si la expresión condicional da como resultado verdadero (true)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;La segunda declaración:&lt;/strong&gt; La expresión, resultado o valor que esperamos obtener si la expresión condicional da como resultado falso (false)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Viéndose de la siguiente manera: &lt;code&gt;expresion_condicional ? primera_declaracion : segunda_declaracion&lt;/code&gt; o &lt;code&gt;condicion ? consecuencia ? alternativa&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;De esta forma, si &lt;code&gt;expresion_condicional&lt;/code&gt; resulta en verdadero (true) entonces la &lt;code&gt;primera_declaracion&lt;/code&gt; es el valor de retorno, pero, si &lt;code&gt;expresion_condicional&lt;/code&gt; es falso (false), el operador retorna la &lt;code&gt;segunda_declaracion&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Debemos tener en cuenta que el uso del operador ternario en lugar de una declaración if-else puede ayudar a tener un código más limpio, conciso y reducido, pero debemos tener cuidado de no realizar múltiples condiciones anidadas u operaciones complejas con el operador, por ello, es típicamente usado para calcular un valor o realizar una selección simple inmediata en los casos en que necesitemos realizarlo condicionalmente. Algunas veces es mucho mejor utilizar las sentencias if-else si las evaluaciones lógicas que estamos realizando son muy complejas, el operador ternario puede complicar la lectura del código y complicar el seguimiento del flujo de ejecución del programa e incluso hacer complejas futuras refactorizaciones.&lt;/p&gt;

&lt;p&gt;Por lo tanto, podemos decir que &lt;code&gt;expresion_condicional&lt;/code&gt; siempre será una expresión booleana.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"El primer valor es mayor que el segundo."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"El segundo valor es mayor que el primero."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;mensaje&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"El primer valor es mayor que el segundo."&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"El segundo valor es mayor que el primero."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Operador ternario anidado
&lt;/h2&gt;

&lt;p&gt;El operador ternario anidado (nested ternary operator en inglés), podemos utilizarlo para declarar más de una condición.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"El primer valor es mayor que el segundo."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"El segundo valor es mayor que el primero."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"El primer valor y el segundo son iguales."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;mensaje&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"El primer valor es mayor que el segundo."&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"El segundo valor es mayor que el primero."&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"El primer valor y el segundo son iguales."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mensaje&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta forma podemos evaluar múltiples condiciones anidando diversas expresiones que permitan obtener el valor correspondiente según el resultado de estas.&lt;/p&gt;

&lt;p&gt;Debemos tener en cuenta que el operador ternario es asociativo por la derecha, lo que nos indica que la sentencia u ocurrencia del operador que vamos a aplicar primero es desde la derecha, es decir, la ultima expresión ternaria que se encuentre al extremo derecho. Por lo tanto, si tenemos una expresión de la forma &lt;code&gt;a ? b : c ? d : e&lt;/code&gt; la evaluamos como &lt;code&gt;a ? b : (c ? d : e)&lt;/code&gt; y no como &lt;code&gt;(a ? b : c) ? d : e&lt;/code&gt;. Esto significa que el resultado de evaluar  &lt;code&gt;(c ? d : e)&lt;/code&gt; va a ser parte de la evaluación &lt;code&gt;a ? b&lt;/code&gt;, por lo que, &lt;code&gt;a ? b : resultado_c_con_d_y_e&lt;/code&gt;. Esto ocurre porque necesitamos conocer los resultados de cada expresión para poder determinar la siguiente evaluación que se realice en el operador ternario, si evaluamos la primera expresión no tenemos seguridad de que el valor devuelto va a ser un booleano, por lo tanto, las expresiones anidadas no podrían suceder de manera adecuada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expresión condicional ref
&lt;/h2&gt;

&lt;p&gt;A partir de la versión 7.2 de C# podemos utilizar la palabra reservada ref para asignar una variable de referencia local de forma condicional con una expresión de referencia condicional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En el código anterior no estamos utilizando la palabra reservada ref, por lo tanto, cuando se efectúa la condición &lt;code&gt;valor ≥ 100&lt;/code&gt;, se obtendrá el elemento en la posición 2 (tercer elemento del array, es decir, 3) o el de la posición 4 (último elemento, es decir, 5) del array, copiando así dicho valor hacia la variable &lt;code&gt;valor2&lt;/code&gt;, por lo tanto, si cambiamos el valor de la variable &lt;code&gt;valor2&lt;/code&gt; a 1000, el array de &lt;code&gt;numeros&lt;/code&gt; enteros se mantiene intacto.&lt;/p&gt;

&lt;p&gt;Ahora realicemos lo mismo pero utilizando ref:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;valor1&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este caso estamos diciendo que la variable &lt;code&gt;valor2&lt;/code&gt; almacenara un valor como referencia, y la expresión condicional está recibiendo como resultado una referencia de un valor, a su vez las posiciones 2 y 4 del array &lt;code&gt;numeros&lt;/code&gt; están siendo devueltas como una referencia, por lo tanto, la variable &lt;code&gt;valor2&lt;/code&gt; ahora no realiza una copia del valor obtenido del array sino que está apuntando mediante una referencia al tercer o último elemento del array de &lt;code&gt;numeros&lt;/code&gt; (posición 2 y 4 respectivamente). De esta forma, si asignamos un nuevo valor a la variable &lt;code&gt;valor2&lt;/code&gt;, lo que estamos haciendo es ir y reasignar el valor almacenado en la dirección de la referencia, como resultado, estaremos modificando el array.&lt;/p&gt;

&lt;p&gt;Antes de C# 7.2 necesitábamos realizar algunas operaciones extra para asignar o enlazar las referencias de una variable a otra de forma condicional, de la siguiente manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="nf"&gt;ObtenerPorReferencia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="n"&gt;valor2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numeros&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ObtenerPorReferencia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;condicion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valorSiVerdadero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;valorSiFalso&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;condicion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;valorSiVerdadero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;valorSiFalso&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos observar ciertas similitudes como que la variable &lt;code&gt;valor2&lt;/code&gt; almacena una referencia, que el método en cuestión devuelve y que los valores obtenidos del array &lt;code&gt;numeros&lt;/code&gt; se pasan por referencia, sin embargo, se alcanza a notar que conlleva un poco más de trabajo y además que en este caso si el array &lt;code&gt;numeros&lt;/code&gt; es nulo o alguna de las posiciones del array es nulo, tendremos un error NRE (Null Reference Exception) porque estas expresiones se ejecutan incondicionalmente como parte del flujo del programa, situación que no ocurre con la forma ternaria debido a que las expresiones son ejecutadas según se cumpla la condición, no antes de evaluarlas.&lt;/p&gt;

&lt;p&gt;En lo que al manejo de tipos por valor o referencia respecta, podemos tener una variable a la que se permita guardar valores por referencia a partir de una expresión condicional que retorne valores por referencia. Es decir, que en lugar de almacenar un valor (10 por ejemplo) almacenamos un “identificador, enlace, lugar, dirección” que contiene la referencia a la variable original, no el valor original, más bien, el espacio de memoria que contiene dicho valor.&lt;/p&gt;

&lt;p&gt;Piénsalo como una caja, donde tú guardas las cosas, la caja es el espacio en memoria, o contenedor, si tú guardas un cuaderno, estás guardando el objeto, con espacio físico y tú sabes que está ahí, y luego ese cuaderno puedes llevarlo a otra caja, o colocar otro cuaderno en una caja distinta, ahora son dos cajas con cuadernos, si le quitas hojas a uno, el cuaderno de la otra caja no se ve afectado, tiene todas sus hojas.&lt;/p&gt;

&lt;p&gt;Pero, si en lugar del cuaderno, en la primera caja guardas un papel que dice donde está el cuaderno, y luego colocas una copia de ese papel en la otra caja refiriendo al mismo cuaderno, cuando tú vayas y busques ese cuaderno en el lugar que has colocado en el papel y arranques unas cuantas hojas, si más adelante lo buscas a partir de cualquiera de los dos papeles, será el mismo cuaderno y tendrá hojas menos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Curiosidades
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;El operador ternario se le conoce así porque trabaja con tres operandos. La palabra "ternario" deriva del latín "ternarius", que significa "compuesto de tres elementos".&lt;/li&gt;
&lt;li&gt;El Elvis Operator en Kotlin en realidad es el null coalesing en C#. En Kotlin el ternary operator se consigue utilizando sentencias if-else, porque estas también pueden ser evaluadas como expresiones, por ejemplo, &lt;code&gt;if (a) b else c&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Python utiliza una sintaxis especial para el ternary operator: &lt;code&gt;resultado if condicion else alternativa&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Otros lenguajes de programación también utilizan &lt;code&gt;?:&lt;/code&gt; como ternario, por ejemplo JavaScript, PHP, JAVA, entre otros.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;El operador ternario es una forma muy útil de reducir la cantidad de líneas de código, pero más aún, de introducir una forma un tanto más declarativa de expresar resultados basados en condiciones, sin embargo, su uso debe ser limitado en cuanto a la cantidad de expresiones que pretendemos evaluar así como la complejidad de estas, no hay nada que reemplace unas buenas sentencias &lt;code&gt;if-else&lt;/code&gt; cuando las evaluaciones lógicas tienden a complicarse, y por el bien de la salud de tu código y de tus compañeros intentando descifrar los enigmas que este esconde, algunas veces es mejor utilizar la forma sencilla y convencional de realizar estas evaluaciones, ya que todos conocen la sentencia if-else, pero no todos pueden conocer el operador ternario.&lt;/p&gt;

&lt;p&gt;Si bien el operador ternario puede variar de lenguaje en lenguaje, como ya has visto anteriormente, lo importante es conocer su existencia, así como el patrón que este sigue, luego, la sintaxis se la dejas al lenguaje en cuestión, pero tú ya sabes como funciona.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código fuente
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials" rel="noopener noreferrer"&gt;Repositorio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrVenturaU/BlogPostTutorials/blob/main/src/BlogPostTutorials.TernaryOperator/BlogPostTutorials.TernaryOperator.Console/Program.cs" rel="noopener noreferrer"&gt;Archivo fuente&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
