Rename Refactoring on Anonymous Types

Hi,

My name is Rahul Bhandarkar and I work on the C# IDE QA team. I have spent most of my time working on the Refactoring and Project System features, in the past I have also worked on Snippets and Edit-and-Continue.

Rename Refactoring is a code refactoring we introduced in VS2005, it allows a user to rename a symbol in code and have its definition and all the references updated.

For example:

public class A

{

   int p;

   void M()

   {

     if (p > 0)

     p = 0;

    }

}

If you Invoke Rename Fefactoring on p and rename it to q, the definition and all references to the symbol p, will now be updated to q.

public class A

{

   int q;

   void M()

   {

     if (q > 0)

     q = 0;

    }

}

Anonymous Types is a new C# 3.0 language feature introduced in VS 2008. An anonymous type is nameless class type that derives from object and has a sequence of read-only properties that are initialized using member-initializers. Anonymous types are immutable, i.e. once they are constructed, the properties are read-only. Let’s look at an example:

var foo = new { A = 1, B = "hello world" };

If you examine the IL that the compiler produces for this, you will see a compiler-generated type with a random name that usually ends with __AnonymousType, and contains two properties, a property A of type int and a property B of type string, both properties only have getters (i.e. they are read-only).

A member-initializer can take the following forms:

Simple Name: var foo = { x };

Member access: var foo = { bar.x };

Explicit Name: var foo = { Prop = x };


Type Unification

The compiler unifies anonymous types that define a sequence of properties of the same type specified in the same order.

Example:

   var order = new {ID = 1, City=”London”}

   var customer = new { ID = 1000, City = “Seattle”}

The variables order and customer have the same underlying anonymous type. A side-effect of this with respect to Rename Refactoring is that a Rename on order.ID will also trigger a Rename on customer.ID.

   var order = new {ID2 = 1, City=”London”}

   var customer = new { ID2 = 1000, City = “Seattle”}

Note that this effect is restricted to the method in which the Rename is invoked in.

Introducing Named Properties

Previously in the C# language we did not have declarations that could also be references. So when we invoked Rename on a symbol we knew exactly if we were trying to rename a definition of a reference. Now with the Simple name member-initializer, we have a situation where “x” is a declaration of the Anonymous Type property and a reference to another local. So what is the effect of renaming “x” ? We decided that only in the case where it was absolutely clear what the user was trying to rename (Explicit Name Member initializer) we would invoked the Rename on the property name. In the other two cases we would treat it as a rename on the reference.

Lets see how that works,

int x = 10;

var foo = { x };

Rename on x at either location will give us.

int x2 = 10;

var foo = { x2 };

But what if there other variables that refer to foo, all of them would have to be modified.

int x = 10;

var foo = new { x };

var bar = new {foo.x};

var m = bar.x;

var baz = new { bar.x };

This would lead to a cascading effect which was undesirable. In order to preserve the semantics of the anonymous type we decided to introduce a named property.

int x2 = 10;

var foo = new { x = x2 };

var bar = new {foo.x};

var m = bar.x;

var baz = new { bar.x };

I find Code Refactoring very interesting and as the language evolves there are several interesting Refactorings that make writing and modifying code easy and fun, after all we are about developer productivity. So I welcome your feedback/suggestions on existing and ideas for new Refactorings.