Which is Better: Using var or the Explicit Type in C#?

In many development teams, there are conversations or even arguments about whether in C# we should use var or the explicit type of an object when declaring variables. 

In this post, we will look at the implications and my opinion on the matter.

 

 

1- Performance Impact When Using var in C#

 

None.

 

Using the var keyword or the explicit type when defining variables has no effect on performance. This is because var does not mean that the type is dynamic; it simply means that the type is inferred by the compiler at compile-time. The technical term in English is "inferred." 

 

Here we can see an example with code in C# and in IL. We see that both versions are identical:

 

var vs type on IL

Therefore, all the implications we might find are visual or relate to the development experience. 

 

 

2 - Should I Use var or the Explicit Type?

 

Since there’s no effect on performance, it all comes down to preference. Before continuing, I want to say that I have a preference, but even so, I would never block a code review if someone uses the other approach, because I understand it’s not a real issue. There are companies that define whether to use var or the explicit type, but it’s not that common.

 

In my case, I use the explicit type almost always and I’ll explain why. 

The use of var seems confusing to me because it’s a complement for the variable name; it’s a way of explaining what type it is, or whether it’s an interface, etc.

 

Many developers justify using var by saying it's easier to refactor. But let’s be honest: when was the last time you refactored a type and had to change it more than a handful of times? That is, almost never. 

 

In fact, at this point, in my opinion, the use of var is a drawback because it hides part of the change. Often, when refactoring a type with var, the code doesn’t break, but the type is actually different. This means the process doesn’t seem to be affected at first glance, but it could still cause a bug. If you have tests and you catch it before production, that’s great, but if not, there’s a good chance something will break in production. 

 

A very simple example is changing a variable from double to decimal, or vice versa, where using var could mask the real type and result in a value with less precision than needed. This actually happened to me not long ago, and the bug made it to production.

double thisIsDouble = 12;decimal thisIsisDecimal = 12;thisIsisDecimal = thisIsDouble; //breaks

That code breaks because the type is explicitly specified. But if you use var it works:

 

var thisIsDouble = 12;decimal thisIsisDecimal = 12;thisIsisDecimal = thisIsDouble; //wroks

The reason it works is that now var is no longer double, it’s decimal. In real-world practice it shouldn’t cause issues, but it could depending on how things work behind the scenes.

 

 

In any case, the main reason I use the explicit type is readability. When it comes to the blog or the YouTube channel, it’s obvious – I talk more or less quickly, and the more information you have on the screen, the better.

 

For example, in this code from one of the tests in my book Complete Guide to FULL STACK DEVELOPMENT with .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";	}}

You can clearly see the type of each variable. Even with good variable names there can still be doubts, and if we use var there would be doubts about the type returned by the GetInMemoryDbContext method. But since we specify the type, we know it’s the normal in-memory DbContext.

 

 

But the same applies in the workplace, where using the explicit type shows the reader what type it is, which greatly facilitates code reviews. Referring back to the previous case, where a user creates a new test, you can see each type. With var, if you were a new person working on that code, you wouldn’t be able to see the type in the code review app, because usually it doesn’t load the whole file. 

 

Another very important example is with values that can be null. Imagine you haven’t seen my post on the importance of good programming and don’t have alerts for warnings enabled.

In this scenario, we return an object that can be null and then access a value on it. If we see the following in a code review, it will probably pass inspection:

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

 

And we access it like this:

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

But if we specify the type, in the review we’ll see it’s a nullable object and therefore before accessing any property we need to verify it’s not null, because otherwise it could throw an exception. So we should check the value, which is much easier to spot in a code review.

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");}

 

Most IDEs have functionality to alert you or highlight errors in yellow or red, making it visually obvious when there’s a problem, but that functionality isn’t available when reviewing code in a web interface. Therefore, in my opinion, using the explicit type makes it easier to read code, which leads to better code reviews and understanding, and for me, that’s a strong enough reason.

 

NOTE: We could discuss whether we should use the coalesce operator to simplify the if; but that's another story. 

 

 

Finally, when defining variables in the latest versions of .NET we now have another alternative. You can specify the explicit type on the left and leave out the type in the right-hand declaration. 

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

This option is becoming more popular and for me, it’s slowly becoming my favorite since it tends to end the debate of using var or the explicit type.

 

This post was translated from Spanish. You can see the original one here.
If there is any problem you can add a comment bellow or contact me in the website's contact form

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

Buy me a coffee Invitame a un café