CA1806: When a method returns a new instance and the instance is ignored

The official title of the CA1806 analyzer warning is “Do not ignore method results,” but this doesn’t really show up in the list of warnings. Instead of showing this generic message, when CA1806 is triggered, it shows very specific text about what triggered the warning.

In this article, I’ll show a few examples of code that triggers the CA1806 warning and how to fix it. At the end, I’ll show one scenario where it doesn’t trigger when it should.

CA1806 – When you call a string method and don’t use the new string

Strings are immutable. Once you create a string, you can’t change that string object. There are many string methods that appear to modify a string, but what they’re really doing is creating a new string object.

When you call these string methods and don’t use the new string they create, you’ll get the CA1806 warning. For example, consider the following code:

string message = "hello"; message.Remove(1); message.Replace("h", "H"); message.ToUpper(); message.Trim(); message.PadLeft(5);
Code language: C# (cs)

This will generate five CA1806 warnings (one for each string method called). Here’s an example of one of the warnings:

CA1806 Main calls Remove but does not use the new string instance that the method returns. Pass the instance as an argument to another method, assign the instance to a variable, or remove the call if it is unnecessary.

To fix this, set the original string variable to the output of the string method. For example:

string message = "hello"; message = message.Remove(1);
Code language: C# (cs)

This is the most important problem that the CA1806 rule catches. This catches a subtle bug. It’s easy to make this mistake, because the method names suggest that they modify the string, when in fact they are returning a new string object with the modifications.

CA1806 – When you call a Linq method without using the results

When you call a Linq method, such as Select(), it doesn’t actually execute until you try to use the results. The execution is deferred.

CA1806 triggers when the Linq method results aren’t set to a variable or used, like this:

string message = "hello"; message.Select(t => char.ToUpper(t));
Code language: C# (cs)

This triggers the following CA1806 warning:

CA1806 ‘Main’ calls ‘Select’ but does not use the value the method returns. Linq methods are known to not have side effects. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.

CA1806 only partially reveals the underlying problem here. The rule won’t trigger if you set the Linq method call result to a variable, even though you’re not actually using the results:

string message = "hello"; var query = message.Select(t => char.ToUpper(t));
Code language: C# (cs)

Does this solve the underlying problem? No, but it does get rid of the CA1806 warning.

The underlying problem is that the Linq method results aren’t being used. To solve the underlying problem, use the results. For example:

string message = "hello"; var query = message.Select(t => char.ToUpper(t)); foreach(var c in query) { Console.WriteLine(c); }
Code language: C# (cs)

CA1806 – When you create an instance of an object without saving the reference to a variable

You’ll get the CA1806 warning when you call a constructor without using the created object, like this:

new RaceCar();
Code language: C# (cs)

This will generate the following CA1806 warning:

CA1806 Main creates a new instance of RaceCar which is never used. Pass the instance as an argument to another method, assign the instance to a variable, or remove the object creation if it is unnecessary.

Chances are this is just a simple mistake and you can simply remove this line.

//new RaceCar(); Most likely you'll just want to remove the line
Code language: C# (cs)

Or you can set the object reference to a variable. This will get rid of the CA1806 warning. But it’s unlikely this is the right solution. Why? Because you probably won’t be using this variable anyway, so it’s better to just get rid of the unnecessary constructor call.

var raceCar = new RaceCar();
Code language: JavaScript (javascript)

CA1806 is not triggered by DateTime methods, but it should be

What I don’t like about the CA1806 analyzer rule is that it’s inconsistent.

Just like strings, DateTimes are immutable. Once you create a DateTime object, you can’t change it. And just like with string methods, there are DateTime methods that return a new DateTime object.

It’s easy to make the mistake of thinking these DateTime methods modify the DateTime object, because the method names definitely suggest that behavior. But they actually return a new DateTime object with the modification.

For example, consider the following code:

DateTime now = DateTime.Now; now.AddDays(1);
Code language: C# (cs)

Strangely, the CA1806 warning is not triggered here, even though the new DateTime object returned by AddDays() is being ignored. AddDays() is not modifying the original DateTime object. It’s returning a new object.

Hopefully one day they’ll extend this CA1806 rule to apply to DateTime, since this would catch this subtle bug just like it does with strings.

Leave a Comment