06 October 2008

ReSharper Combos - Hiding Details

Today my day started with the question from Oleg Stepanov, Project Manager of ReSharper. He asked about avoiding huge amount of manual code changes, and after short discussion we got it done with ReSharper. I was very excited! We were able to solve refactoring task in seconds, invent new refactoring combo, and ReSharper was so smart to handle it absolutely right. No manual code changes outside of the type being refactored. Here is simplified version of what we had, what we were to accomplish and how we did it.

  public class Person
  {
    public string Name { get; set; }
    public int Age { get; set; }
  }
 
  public class PersonInformation
  {
    private readonly Person myPerson;
 
    public PersonInformation(Person person)
    {
      myPerson = person;
    }
 
    public Person Person
    {
      get { return myPerson; }
    }
  }
 
  internal class Processor
  {
    private readonly PersonInformation myPersonInformation;
 
    public Processor(PersonInformation personInformation)
    {
      myPersonInformation = personInformation;
    }
 
    public int Process()
    {
      switch (myPersonInformation.Person.Name)
      {
        case "Mike":
          return 1;
        case "Sally":
          return myPersonInformation.Person.Age > 30 ? 2 : 3;
      }
      return myPersonInformation.Person.Age < 20 ? 0 : 1;
    }
  }

Consider PersonInformation class above. We wanted to decouple it from Person class and make it store Name and Age itself. However, we had a lot of usages like in Processor.Process, where Person property was being used to access Name and Age. How would we do it?

First, we use Generate (Alt-Ins) and select Delegating Members to generate Name and Age properties in PersonInformation class:

    public string Name
    {
      get { return myPerson.Name; }
      set { myPerson.Name = value; }
    }
 
    public int Age
    {
      get { return myPerson.Age; }
      set { myPerson.Age = value; }
    }

Then we change Person Property to return PersonInformation instead. Since there are all required properties already, usages are not broken. They are now routed through delegating members and use Name and Age properties of PersonInformation:

    public PersonInformation Person
    {
      get { return this; }
    }

And here magic happens, we use Inline Property refactoring to get rid of the property!

  public class Person
  {
    public string Name { get; set; }
    public int Age { get; set; }
  }
 
  public class PersonInformation
  {
    private readonly Person myPerson;
 
    public PersonInformation(Person person)
    {
      myPerson = person;
    }
 
    public string Name
    {
      get { return myPerson.Name; }
      set { myPerson.Name = value; }
    }
 
    public int Age
    {
      get { return myPerson.Age; }
      set { myPerson.Age = value; }
    }
  }
 
  internal class Processor
  {
    private readonly PersonInformation myPersonInformation;
 
    public Processor(PersonInformation personInformation)
    {
      myPersonInformation = personInformation;
    }
 
    public int Process()
    {
      switch (myPersonInformation.Name)
      {
        case "Mike":
          return 1;
        case "Sally":
          return myPersonInformation.Age > 30 ? 2 : 3;
      }
      return myPersonInformation.Age < 20 ? 0 : 1;
    }
  }

Look how Processor now uses Name and Age directly on PersonInformation class and has no idea about Person class used inside! Now the fact that PersonInformation uses Person is implementation detail and we can change it any way we like.

Refactor With Pleasure!

3 comments:

Sean Kearon said...

Very elegant indeed! There's a pattern in there somewhere. Bringing the values of the replacing type into the type that is to be removed and then inlining. It reminds me of working with equations in mathematics where you make a substitution so as to simplify and then cancel down to reveal a more elegant result. But hey, it's a long time since I've done any maths!!

Anonymous said...

Hi there not sure where to ask this question but I was wondering when Resharper 4.5 M1 is due for release? I saw that it was initially supposed to be October 13th but there hasn't been a mention of it. Lately I notice it really slows down the system that I often have to disable the addin when debugging then enable it back on when coding

Anonymous said...

Just following you from Tess blog :-) I see that the website is up now, link was broken because of change in name server so you should be able to download sos2.dll from
http://debuggingblog.com/wp