I also said it would be nice if ReSharper could separate the assignments onto separate lines… and got reply from Jenya Legkiy who works at JetBrains who said it already does.
So to make up for it I’ve done my first screencast to show how you can you use ReSharper to refactor your code to use an object initializer and then go back to having the assignments on separate lines.
Recently I took on some work for a company to do some work on an ASP.NET web site.
As with any first project for a client I wanted to make a good impression and produce quality work and deliver on time.
Getting Started
When I started work on the project I noticed the previous developers had created a web site project rather than a web project.
Seeing this as a long term project, I converted the website solution into a web project. It was easy and took no time at all.
Then I noticed business logic and data access code was embedded into the ASPX files, which in my opinion is a code smell.
So I started cleaning up the solution by moving the code into code behind files.
A bridge too far
After a couple of hours refactoring I realised this was going to take days not hours. So I stopped and asked myself the question: How much value is there for my client in what I’m doing?
What if at the end of day one the client asked how I had got on? By showing them a mock up, prototype or anything else which showed progress I would be able to give them confidence they had picked the right man for the job.
If I started talking down the previous developers, and how I’d spent the budget on moving code around on a site that was working I might shatter their confidence in me.
So I was stuck between working with a painful solution and providing value to the client.
You can still be a Software Craftsman
I decided only to clean up pages that I actually had to modify. This limits the upfront cost in sorting out the whole solution and delivers value to the client sooner.
I believe the ability to bite your tongue, hold back one’s reservations and make the best out of a bad situation is a required skill for a good developer. This doesn’t mean selling your soul but simply that you understand that delivering value is the most important thing for your client.
By being a good boy scout and making small incremental changes, one day you will have a code base you’re happy with. And from day one your client can feel confidence in you through the value they can see being delivered.
But as I’ll demonstrate in this post you can have too much of a good thing.
When object initializers go bad
The code below shows an example of mapping a model object from a data reader with and without using an object initializer.
using System;
using System.Data;
public class Mapper
{
public static Model Map(IDataReader reader)
{
if (reader.Read())
{
Model model = new Model();
model.FirstName = reader[0].ToString();
model.LastName = reader[1].ToString();
model.Age = Convert.ToInt32(reader[2].ToString());
return model;
}
return null;
}
public static Model MapUsingObjectInitializer(IDataReader reader)
{
if (reader.Read())
{
return new Model
{
FirstName = reader[0].ToString(),
LastName = reader[1].ToString(),
Age = Convert.ToInt32(reader[2].ToString())
};
}
return null;
}
}
public class Model
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
If we run two unit tests to map the model from a data reader we will get two passing tests.
using System.Data;
using NUnit.Framework;
[TestFixture]
public class When_Mapping_Model_Using_DataReader
{
[Test]
public void Should_Be_Able_To_Map_Model()
{
Mapper.Map(GetDataReader());
}
[Test]
public void Should_Be_Able_To_Map_Model_Using_Object_Initializer()
{
Mapper.MapUsingObjectInitializer(GetDataReader());
}
public static IDataReader GetDataReader()
{
DataTable table = new DataTable();
DataRow row = table.NewRow();
table.Columns.Add(new DataColumn("FirstName"));
table.Columns.Add(new DataColumn("LastName"));
table.Columns.Add(new DataColumn("Age"));
row["FirstName"] = "Bob";
row["LastName"] = "Smith";
row["Age"] = "55";
table.Rows.Add(row);
return new DataTableReader(table);
}
}
Now if we modified the GetDataReader method to return a string value for age
We get a failing test when mapping without an object initializer as shown below
As you can see from the output message above we can easily find the line of code (line 13) that caused the exception.
When a test fails for the code using an object initializer
the line of code that caused the exception (line 23) is the same one in which the object was created.
The fact is the more properties you initialize using an object initializer the harder it will be to find the one that causes an exception.
What’s ReSharper got to do with this?
In a word temptation. It makes it so easy to convert your code to use one.
That’s not ReSharpers fault
I agree. Ultimately it’s a developers choice if they want to use the refactoring that tools like ReSharper suggest, after all just because you can doesn’t mean you should.
However it could give you an option not to convert to object initializer if more than say ten properties were going to be initialized.
Or detect if the object initializer wasn’t a straight forward mapping and then not suggest using one like in this example.
What ReSharper is missing
What would be really useful if you could convert code that was using an object initializer to the classic way of setting properties one line at a time.