Puedes ver el contenido de este vídeo junto con su curso en el modo vídeo (similar a Udemy) si pulsas aquí.

Qué es mejor, utilizar var o el tipo en C#

17 Feb 2025 10 min (0) Comentarios

En muchos equipos de desarrollo hay conversaciones o incluso peleas sobre si en C# debemos utilizar var o el propio tipo de un objeto cuando declaramos variables. 

En este post, vamos a ver las implicaciones y mi opinión al respeto.

 

 

1- Efecto en el rendimiento al utilizar var en c#

 

Ninguno.

 

El uso de la keyword var o el tipo concreto a la hora de definir variables no tiene ningún efecto al rendimiento, esto es debido a que var no significa que el tipo sea dinámico, sino que en tiempo de compilación utiliza dicho tipo. La palabra técnica en inglés es inferred, ni idea en castellano. 

 

Aquí podemos ver un ejemplo con el código en C# y en IL, vemos que ambas versiones son iguales:

 

var vs type on IL

Por lo tanto, todas las implicaciones que podamos tener son visuales o a la hora de desarrollar. 

 

 

2 - Debo usar var o el tipo concreto? 

 

Dado a que no hay ningún efecto en el rendimiento, todo pasa a ser un tema de preferencia. Antes de continuar quiero decir que yo tengo una preferencia y pese a ello, nunca pararé una revisión de código si alguien utiliza la otra, ya que entiendo que no es un problema. Hay empresas que tienen definido el uso de var o el tipo concreto, pero no suele ser lo común.

 

En mi caso yo utilizo el tipo concreto prácticamente siempre y voy a explicar por qué. 

El uso de var me parece confuso porque es un complemento al nombre de la variable, es una forma de explicar que tipo es, o si es una interfaz, etc.

 

Muchos desarrolladores justifican el uso de var diciendo que es más fácil hacer una refactorización. Pero seamos sinceros, cuándo fue la última vez que tuviste que refactorizar, y no solo eso, refactorizar un tipo y tenerlo que cambiar más de un puñado de veces? Pues eso, casi nunca. 

 

De hecho, en este punto, en mi opinión el uso de var es malo, ya que oculta parte del cambio, muchas veces al refactorizar un tipo con var, el código no rompe, pero el tipo es distinto, lo que quiere decir que el proceso que sucede en ese momento a priori no se ve afectado, pero puede ser que sí lo esté y tengamos un bug. Si tenemos tests y lo cogemos antes de llegar a producción sería maravilloso , pero si no, es muy posible que rompa algo en producción. 

 

Un ejemplo muy sencillo es el caso de cambiar una variable de double a decimal, o viceversa, donde el uso de var podría enmascarar el tipo real y por ello terminar con un valor de precisión menor al necesario. Esto me pasó, no hace muchos meses y el bug llegó a producción.

double thisIsDouble = 12;
decimal thisIsisDecimal = 12;

thisIsisDecimal = thisIsDouble; //breaks

Ese código se rompe, porque tienes el tipo especificado. Pero si utilizas var funciona

 

var thisIsDouble = 12;
decimal thisIsisDecimal = 12;

thisIsisDecimal = thisIsDouble; //wroks

El motivo por el que funciona es que ahora var, ya no es double, sino que es decimal. En la práctica real no debería causar problemas, pero puede causar debido a como funcionan por detrás.

 

 

En cualquier caso, el motivo principal por el que yo utilizo el tipo concreto es la legibilidad, en el caso del blog o el canal de youtube es obvio, hablo mas o menos rápido y cuanta más información tengáis  en la pantalla mucho mejor.

 

Por ejemplo en este código de uno de los test dentro de mi libro la Guía completa de DESARROLLO FULL STACK con .NET:

namespace FlagX0.UnitTests.Web.Business.UseCases.Flags
{
	public class AddFlagUseCaseTest
	{

		[Fact]
		public async Task WhenFlagNameAlreadyExist_ThenError()
		{
			//arrange
			IFlagUserDetails flagUserDetails = new FlagUserDetailsStub();
			ApplicationDbContext inMemoryDb = GetInMemoryDbContext(flagUserDetails);

			FlagEntity currentFlag = new FlagEntity()
			{
				UserId = flagUserDetails.UserId,
				Name = "name",
				Value = true
			};

			inMemoryDb.Flags.Add(currentFlag);
			await inMemoryDb.SaveChangesAsync();

			//Act
			AddFlagUseCase addFlagUseCase = new AddFlagUseCase(inMemoryDb, flagUserDetails);
			var result = await addFlagUseCase.Execute(currentFlag.Name, true);

			//assert
			Assert.False(result.Success);
			Assert.Equal("Flag Name Already Exist", result.Errors.First().Message);
		}

		[Fact]
		public async Task WhenFlagDoesNotExist_ThenInsertedOnDb()
		{
			//arrange
			IFlagUserDetails flagUserDetails = new FlagUserDetailsStub();
			ApplicationDbContext inMemoryDb = GetInMemoryDbContext(flagUserDetails);

			//act
			AddFlagUseCase addFlagUseCase = new AddFlagUseCase(inMemoryDb, flagUserDetails);
			var result = await addFlagUseCase.Execute("flagName", true);

			//assert
			Assert.True(result.Success);
			Assert.True(result.Value);
		}


		private ApplicationDbContext GetInMemoryDbContext(IFlagUserDetails flagUserDetails)
		{
			DbContextOptions<ApplicationDbContext> databaseOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
				.UseInMemoryDatabase("flagx0Db")
				.Options;

			return new ApplicationDbContext(databaseOptions, flagUserDetails);
		}
	}

	public class FlagUserDetailsStub : IFlagUserDetails
	{
		public string UserId => "1";
	}
}

Se puede observar perfectamente de que tipo es cada variable, incluso teniendo buenos nombres de variables siempre puede haber dudas, si utilizamos var, habría dudas a la hora de saber que tipo es el resultado del método GetInMemoryDbContext, pero como tenemos el tipo, sabemos que es el DbContext normal en memoria.

 

 

Pero lo mismo aplica en el entorno laboral, donde el uso del tipo concreto indica al lector que tipo es, lo que facilita mucho una revisión de código, si volviéramos al caso anterior, donde un usuario crea un nuevo test, podemos ver cada tipo, con var, si fuéramos una persona nueva trabajando en dicho código no podríamos ver en la app de la revisión de código que tipo es, ya que normalmente no cargan el fichero entero. 

 

Otro ejemplo muy importante es con valores que pueden ser nulos. Imagina que no has visto mi post sobre la importancia de programar bien y no tienes alertas para los warnings.

En este supuesto, devolvemos un objeto que puede ser nulo y en ese objeto accedemos a un valor, si vemos lo siguiente en una revisión de código la vamos a dar como buena:

public async Task<FlagEntity?> GetByName(string flagname)
    => await applicationDbContext.Flags
        .Where(a => a.Name.Equals(flagname, StringComparison.InvariantCultureIgnoreCase))
        .AsNoTracking()
        .FirstOrDefaultAsync();

 

Y accedemos de la siguiente forma:

public async Task<Result<FlagDto>> Example(string name)
{
    var entity = await GetByName(name);
    return entity.ToDto();
}

Pero, si especificamos el tipo, veremos en la revisión que es un objeto nulable y por lo tanto antes de acceder a cualquiera de sus propiedades necesitas verificar que el valor no es nulo porque podría saltar una excepción, por lo que debemos comprobar el valor, lo cual es mucho mas sencillo de ver en una revisión de código.

public async Task<Result<FlagDto>> Example(string name)
{
    var entity = await GetByName(name);
    if (entity != null)
    {
        return entity.ToDto();
    }

    return Result.NotFound<FlagDto>("FlagDoes not exist");
}

 

La gran mayoría de IDEs traen la funcionalidad de sacarnos una alerta o mostrarnolo de color amarillo/rojo, para que veamos con los ojos que hay un fallo, pero esa funcionalidad no está disponible a la hora de revisar el código en una interfaz web. Por lo tanto, en mi opinión el uso del tipo concreto facilita la lectura del código, lo que hace que se revise y entienda mejor y para mi es motivo más que justificado.

 

NOTA: Podríamos entrar a discutir si debemos reducir el if con el coalesce operator; pero eso es otra historia. 

 

 

Finalmente, a la hora de definir variables en las últimas versiones de .NET tenemos la última alternativa.  Donde podemos indicar el tipo concreto en la izquierda y podemos ignorar el tipo en la declaración del lado derecho. 

FlagDto testFlagVar = new()
{
    Name = "example",
    IsEnabled = true,
    Id = 1
};

Esta opción se ve cada vez más y para mi poco a poco está siendo mi favorita ya que suele acabar con el debate de utilizar var o el tipo.

 

Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café