Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

C# 2.0 Code Refactoring : Page 3

The next version of Visual C# will include a code refactoring tool that can make productivity-enhancing changes to the layout and structure of your code, such as extracting interfaces or encapsulating a field, and can automate common coding tasks.


advertisement
Figure 6. The Encapsulate Field Dialog: This dialog lets you name the property that wraps the member, set the property's visibility, and instruct how to update current references to the member.
Field Encapsulation
This handy refactoring feature allows you to generate a property around a class member. You can use it to encapsulate a public field or to expose a private field as public property. For example, suppose you want to expose the m_Number member variable as a public property:

public class MyClass { int m_Number; }



Place the cursor on m_Number and select Encapsulate Field... from the Refactor menu. This will bring up the Encapsulate Field dialog box shown in Figure 6.

EncapsulateField can recognize a commonly used member variable naming convention and generate the appropriate property name out of it. Meaning, if the member variable is prefixed with m_ or just _, the Encapsulate Field will omit that prefix when suggesting a property name. Of course, you can specify any property name you like. You can also specify the property's visibility (public, internal, protected internal, protected, private), and what should be done with external
Figure 7. Change Method Signature Dialog: This dialog lets you change, add, or remove method parameters.
references: You can have the refactoring tool replace all references to the field (inside the type or outside) with references to the new property. Although the default reference update selection is set to External, I recommend always choosing All, because that will promote looser internal coupling in the type itself and that makes maintenance easier. Any business rule enforced by the property later on will apply automatically inside the type. You can choose if you want to review the changes to the references and apply the change. The result will be a public property wrapping the member:

public class MyClass { int m_Number; public int Number { get { return m_Number; } set { m_Number = value; } } }

You can use the field encapsulation capability to do just what its name implies. For example, instead of this public member variable...


public class MyClass { public int m_Number; }

...after using field encapsulation refactoring, you will end up with a public property called Number, and the public m_Number member will be converted to a private member:

public class MyClass { private int m_Number; public int Number { get {...} set {...} } }

Note that there is no refactoring support for generating an indexer or an iterator (another C# 2.0 feature). Unfortunately, Microsoft's design for encapsulation of an event field is poor. C# supports event accessors, which are property-like accessors encapsulating access to delegates. In my opinion, exposing member delegates in public should be explicitly forbidden by your C# coding standard. For example, instead of this definition:

public class MyPublisher { public event EventHandler m_MyEventHandler; }

You should write:

public class MyPublisher { EventHandler m_MyEventHandler; public event EventHandler MyEventHandler { add { m_MyEventHandler += value; } remove { m_MyEventHandler -= value; } } }

Unfortunately, when you apply the field encapsulation refactoring selection to an event, it will generate the following invalid code:

//Invalid refactoring code public class MyPublisher { private event EventHandler m_MyEventHandler; public EventHandler MyEventHandler { get { return m_MyEventHandler; } set { m_MyEventHandler = value; } } }

Be sure to always encapsulate your events, even without refactoring support.

Signature Change
Refactoring allows you to change the signature of a method by adding or removing parameters, and refactoring allows you to change the order of parameters. However, you cannot change the method returned type. You can change the signatures of methods, indexers, and constructors. For example, suppose you want to change the Add() method in this Calculator class to use double instead of int parameters:

public class Calculator { public int Add(int number1,int number2) { return number1+number2; } }



Figure 8: Surrounding With Option: Selecting a statement to surround a code selection with.
Right-click anywhere inside the method and select Change Method Signature... from the Refactor popup menu to bring up the Change Method Signature dialog box shown in Figure 7.

Use the dialog to change the order of parameters by moving parameters up or down, add or remove a parameter, and edit a parameter type and name.

For example, select the number1 parameter and click the Edit... button to bring up the Parameter dialog box. Change the parameter type to double. Note that the Parameter dialog will only let you change the type to one of the pre-defined C# types, such as int or string. Next, the Parameter dialog will warn you that the change you are about to do may render existing code invalid. Once you apply the signature change, you need to manually change the Add() method's returned type to double, as well as all its call sites. I find signature change to be of little practical value because it is usually faster to just change the signature manually using the code editor.

Figure 9: A For Each statement surrounding a Trace statement. After injecting the code template, you need to provide actual values for the place holders.
Surround With and Expansions
The last two refactoring features—Surround With and Expansions—are about code typing automation rather than code layout and structure.

Surround with generates a template with blank place holders for commonly used statements (such as foreach or exception handling) around a selected code section. For example, to automatically generate a foreach statement around a trace statement, highlight the statement, right-click, and select Refactor from the pop-up menu, then choose Surround With... and then select For Each, as shown in Figure 8.

It is important to understand that Kill() is not the same as Dispose(). Kill() handles execution flow such as application shutdown or timely termination of threads, whereas Dispose() caters to memory and resource management and disposing of other resources the WorkerThread class might hold. The only reason you might have Dispose() call Kill() is as a contingency in case the client developer forgets to do it.

This will insert a foreach statement where you need to fill in the blanks, by tabbing through them, as shown in Figure 9.

Figure 10. The Insert Expansion Option: The figure shows the process to select a statement for the code expansion operation.
You can use the surround with statement to generate code for the following statements: If, Else, For, For Each, While, Do While, Region, and Try...Catch.

The Expand feature injects template code in-place. When you use Expand with control statements such as For Each, there is no need to surround existing code—it will simply expand a foreach statement where you need to fill in the blanks, similar to Figure 10. You can also use it to expand a multitude of code snippets from a static Main() method, (returning int or void, referred to as SIM and SMV respectively) to an enum definition. For example, to inject a reverse for statement, select Insert Expansion... from the Refactor menu. This will pop-up a scrollable list box, with the possible expansions. Select for from it, as shown in Figure 10.

Table 1 shows the available code expansions in Visual C# 2.0.

Table 1. Code Expansion Statements: The table lists the code expansion statements available to you when refactoring in C# 2.0.

Expansion

Description

namespace

Expands a namespace definition

interface

Expands an interface namespace definition

class

Expands a class definition

struct

Expands a struct definition

~

Expands a C# destructor (defensive Finalize() method)

enum

Expands a enum definition

property

Expands a property definition

indexer

Expands an indexer definition

#if

Expands a conditional compilation section

Using

Expands a using statement

Checked

Expands a checked code block

Unchecked

Expands a unchecked code block

Unsafe

Expands a unsafe code block

Switch

Expands a switch statement

Forr

Expands a reversed for loop

For

Expands a for loop

If

Expands an if statement

Else

Expands an else statement

While

Expands a while loop

Do

Expands a do/while loop

Foreach

Expands a foreach loop

try/catch

Expands a try catch block

Sim

Expands a static integer Main() method

Svm

Expands a static void Main() method

#region

Expands a region definition

Lock

Expands a lock statement


Selecting an expansion type expands the code template shown in Figure 11, where you have to tab through the fields and fill in the blanks.



Juval Löwy is a software architect and the principal of IDesign, a consulting and training company focused on .NET design and .NET migration. His latest book is Programming .NET Components (O'Reilly, 2003). Juval is Microsoft's Regional Director for the Silicon Valley, helping the industry adopt .NET. Juval is a frequent speaker at the major international software development conferences. Contact him at http://www.idesign.net, where you can download his C# Coding Standard..
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Thanks for your registration, follow us on our social networks to keep up-to-date