July 18, 2011, 4:05 a.m.
posted by geist
You sometimes need to change your method signatures by removing an item, adding a local variable as a parameter, or by reordering the existing parameters. These changes require that all calls to the method also be changed. Doing this manually can introduce new bugs into the code. For example, suppose you want to swap the order of two parameters with the same type (int, for example). If you forget to change a call to the method, it may still work; it just won't work right. These bugs can be challenging to find. Therefore, Visual Studio provides refactoring operations for removing, promoting, and reordering parameters.
The Remove Parameters refactor operation allows you to select one or more parameters from a given method, constructor, or delegate and have it removed from the method. It also works to update any callers to the method and remove the value passed to the parameter.
You invoke the Remove Parameters operation by positioning your cursor inside the method signature and then selecting the Remove Parameters menu item from the Refactor menu. You can also get to this operation through the context menu (right-click). In addition, this operation is available from the Class Designer from inside both the class view and the class details view.
Let's look at an example. Suppose you have a method with the following signature:
public static Order GetCustomerOrder(int customerId, int orderId)
This method returns an Order object based on both a customer and an order identification number. Suppose you determine that the order ID is sufficient for returning an order. In this case, you invoke the Remove Parameters refactor and are then presented with the Remove Parameters dialog box (see Figure). Method parameters are listed at the top. To remove one, you select it and click the Remove button. The item to be removed is then updated with a strikethrough. If you change your mind, you can use the Restore button to cancel individual parameter removals.
19. The Remove Parameters dialog box.
When you are ready to make the removal, you can choose to preview the changes or simply apply them all at once. The preview option works the same as other previews. It simply shows you each change in a tree view and allows you to see the details behind the change. You can, of course, also uncheck specific changes. When finished, you apply the final set of removals to your code.
It is common to declare a local variable inside a method and pass that local variable as a call to another method. If you use the refactoring operation to remove the parameter on the method you are calling, the local variable still exists in your calling method. Be careful to make sure that this is what you intended; if not, you will have to remove the local variable manually.
Promote Local to Parameter
One common developer activity is to take a variable from within a method and make it a parameter of the method. As an example, you might look up a value inside a method and assign that value to a local variable. Instead of doing the lookup inside the method, you might want to have the value passed to the method (perhaps you would use the Extract Method refactor to push the value assignment to a new method).
This change of taking a local variable and creating a parameter can be done automatically via the Promote Local Variable to Parameter refactoring operation. It allows you to select a local member of a given method and promote it to a parameter of the method. The tool also works to update any callers of the method.
You invoke the Promote Local Variable to Parameter operation by positioning your cursor on a line of code that declares a variable. You then select the Promote Local Variable to Parameter menu item from the Refactor menu. You can also get to this operation through the context menu (right-click).
To invoke the Promote Local Variable to Parameter operation from the keyboard, first position your cursor on the line of code that contains the variable declaration. Next, play the keyboard chord Ctrl+R, Ctrl+P.
You can promote locals only where they have been initialized. Otherwise, the operation gives an error because it does not know how to update callers to the method. In fact, if the declaration and initialization are on separate lines of code, you cannot use the refactor. This refactoring method works best when both declaration and initialization (assignment) are done on the same line.
Let's walk through an example. Suppose you have a method that takes an order ID and returns an Order object, as in the following method signature:
public static Order GetCustomerOrder(int orderId)
When looking through this method, you notice that there is a variable assignment that retrieves a customer ID as follows:
int customerId = GetCustomerId(orderId);
Suppose you determine that looking up a customer ID from an order ID is very inefficient for a couple of reasons. First, you already should know the customer ID before calling the method. Second, you plan to look up the order inside this method. By looking up the customer ID from the order, you look up the order twice. Therefore, you identify this variable assignment as a good candidate for promoting to the method signature. To do so, you first must right-click the line of code that does the assignment and then choose Promote Local Variable to Parameter from the Refactor context menu.
In this case, there is no preview of the change. Instead, Visual Studio does the refactor. The assignment is removed from the method. The method signature is changed to read as follows:
public static Order GetCustomerOrder(int orderId, int customerId)
In addition, clients who called into this method also get updated. In this case, a call to GetCustomerOrder would now include the code that previously did the variable assignment, GetCustomerId(orderId). The following is an example:
Order newOrder = Customer.GetCustomerOrder(odrId, GetCustomerId(orderId));
One negative here is that the code that called to the Customer object defined the order ID variable with the name odrId. Refactoring used the variable assignment code which defined order ID as orderId. This will result in a compile error that you will have to fix manually. Of course, this would not be the case with constants or in situations in which you use consistent variable names to mean the same thing.
Some Promoting Tips
Constants work as the best type of local variable for promoting to parameters. The reason is that there is no issue with updating calling clients. If you have a local variable with a constant value assigned, you can update callers with that set value.
When you promote a variable that includes an object call in the assignment, however, you will get the warning dialog box shown in Figure. Promoting a variable whose assignment is the result of a call to another method requires that callers that require an update as a result of the promotion should also be able to call the object that does the assignment.
20. Promoting warning.
As an example, suppose you have the variable declaration and assignment as follows:
int CustomerId = GetCustomerFromOrder(orderId)
If you promote CustomerId to a parameter, callers to the method will have to have a reference to the object that contains GetCustomerFromOrder. If they do not, you will end up with a compiler error (and hence the warning). Whether this is an issue depends on how you've organized your code and reference.
When you promote a local variable as a parameter, the parameter is attached to the end of the function signature. This may be your intention. However, you might want to order things differently for better code readability and maintenance. To do so, you would then combine the Reorder Parameters refactor with the promotion. We will look at this operation next.
You move parameters around in a method typically just for readability and maintenance. You might want the more important parameters to appear first on the method signature, or you might try to keep the order similar across like methods or overloads. The Reorder Parameters refactor operation allows you to change the order in which parameters exist on a given method, constructor, or delegate. It also works to update any callers to the method and rearrange the parameters passed on the call.
You invoke the Reorder Parameters operation by positioning your cursor inside the method signature that contains the parameters you want to reorder and then selecting the Reorder Parameters menu item from the Refactor menu. You can also get to this operation through the context menu (right-click). In addition, this operation is available from the Class Designer.
To invoke the Reorder Parameters operation from the keyboard, first position your cursor in the method that contains the parameters you want to rearrange. Next, play the keyboard chord Ctrl+R, Ctrl+O.
Let's look at an example. Suppose you just ran the Promote Local Variable example that promoted a customer ID local to a parameter of the method. The following is the method signature for reference:
private static Order InitCustomerOrder(int orderId, int customerId)
This method is called InitCustomerOrder. Suppose that because customer comes first in the method name, you want to make that the first parameter of the method. To do so, you position the cursor on the method and invoke the Reorder Parameters refactor. This presents the Reorder Parameters dialog box.
This dialog box allows you to modify the order of the parameters on the given method. At the top, it lists all the parameters of the method. To the right of this list, there are two buttons. The up-arrow button moves the selected parameter in the list up. The down arrow does the opposite. You use these buttons to get the order of the parameters the way you want them. Figure shows this example loaded into the Reorder Parameters dialog box.
21. The Reorder Parameters dialog box.
Notice that as you change parameter order, the resulting method signature is displayed below the parameter list. You also have the option to preview any changes that will be made to callers of the method. Clicking the OK button will apply the changes to both the method and its callers.