Refactoring – a new feature in the Visual C# 2.0 IDE
Renaming variables:
Assume you have a solution containing about 25 classes (we’ll also assume that each class is in a separate source file – that means 25 .cs files).
Suppose one class has a variable xyz, which you now want to rename to something more meaningful. In Visual Studio .Net 2003, what options did you have? You could do a find and replace for “xyz” (to rename it to something else, says “username”), but this would also rename variables like “abcxyz” to “abcusername”! You could of course choose the “Find whole word” option, but another problem – this would also rename variables named “xyz” in other classes which you might not want to touch.
The Visual C# 2005 IDE has a new feature which you can use. Lets look at the screen shot below:
In the above image, I want to rename the "username" variable. Within the Visual C# 2005 IDE, I right click on the variable name. Within the context menu that pops up, I choose "Refactor" and then "Rename". A dialog box pops up as shown in the image below:
I type in the new variable name. Suppose I type in "newusername". The IDE determines what all changes have to be made within the solution. Look the image below. You’ll see that both instances of "username" have been changed to "myusername".
What’s so great you might ask – after all, this could have been done by a simple find and replace. You’re right – but that would have worked only for this simple case. Assume "username" was a public variable, and was being used by other classes too. On renaming the variable using the refactoring method above, all the places where the variable was being used (within the current solution), would get renamed to the new name.
Generating get/set accessors for variables
One of the practices that should be followed while programming, is that variables should rarely be made public.
|
If a variable needs to be accessed / modified by other classes, you should expose properties for doing so. This way, within the SET property, you can perform any validation, and thus prevent invalid values being assigned to your variables.
So, for a variable "username", you would write code like:
private string username;
public string Username
{
get { return username; }
set
{
//perform any validation if needed
username = value;
}
}
Man, that’s a lot of code for one variable! Assume you ha to add 30-40 variables in your class, you’d spend a really long amount of time writing the get / set properties for each.
Here’s where the C# 2005 IDE can help you out. What you can do is, initially, just add the variables (without the get and set properties). Then, right click on each variable for which you want to control access, choose "Refactor", and then "Encapsulate Field". You will be prompted for the name of the property, after which, the code for get and set will be auto generated for you.
And what if you have already been using that variable in your other classes directly? No problem – the IDE will automatically update those references to use the newly generated properties instead. Cool!
Implementing Interfaces
Assume you have an interface containing say, 30 functions.
|
You now want to write a class that implements this interface, but don’t have the enthusiasm to implement all 30 functions (you just want to implement a couple for them for quick testing). What do you do? You cant just implement the ones you’re interested in – the compiler will never let you hear the end of it). Fortunately, the C# 2005 IDE gives you a way out. Here’s what you do – declare your class that implements the interface. Then, right click on the interface name, and choose the option "Implement interface", and voila! The stubs are created for you.
You must have seen that there’s also an "Implement Interface Explicitly" option. What does that do? Well, that just puts the Interface name in front of the function name or property name which is being implemented – because, there might be situations where a class is implementing two interfaces, and both the interfaces have a function foo(), and in your class, you might want to provide separate implementations for foo() depending on the interface through which it is invoked. In that case, you will need to inform the compiler as to which implementation is for which interface. The image below should make things clearer:
As you can see, the IsUsernameValid() function definitions are now prefixed by the Interface names. (The above code was generated by right clicking on the interface name and choosing "Implement Interface Explicitly".
Extracting methods for repeated code
First let me show you some code, I’ll then explain what it does and how I want to modify it, and how refactoring can help.
class TestClass
{
public void SendChatMessage(string message)
{
string filtered_message = message;
filtered_message = filtered_message.Trim();
filtered_message = filtered_message.ToUpper();
filtered_message = filtered_message.Replace("<some vulgar word>", string.Empty);
SendMessageOverNetwork(filtered_message);
}
public void SendMessageOverNetwork(string filtered_message)
{
//sends message over the network.
}
}
Ok, lets see what the code does.
|
There is a function called SendChatMessage, that takes a string. What this function is supposed to do is, take a string, which represents a message entered by a user in some chat application, and then calls a function SendMessageOcerNetwork to send it over the network. However, before it does that, it also "cleans" up the string a little bit, ie., it trims it, converts it to upper case (just for illustration purposes), and then removes occurrences of some words which are assumed to be too obscene to send to the other user.
Now, the code that performs the clean up above might also need to be used from other places within the application. Rather than duplicate this code everywhere, you decide to extract it to an auxiliary function, which you can then call from anywhere within your application. How can refactoring help you here? Easy. Just highlight the first 4 lines in the function above, choose "Refactor", and then "Extract method". Have a look at the images below and see how the code gets transformed.