Resharper (or Visual Studio) shortcut to cascade changes to a constructor
Here is a common refactoring that I don't believe I have seen a shortcut for:
Imagine we have a base class with a number of inheriting subclasses. The base classes uses constructor injection to accept a number of services:
class FooBase
{
private IMyService _myService;
private IMyOtherService _myOtherService;
public FooBase(IMyService myService, IMyOtherService _myOtherService)
{
_myService = myService;
_myOtherService = myOtherService;
}
}
class FooConcrete : FooBase
{
public FooConcrete(IMyService myService, IMyOtherService _myOtherService)
base(myService, myOtherService)
{
}
}
Notice how FooConcrete has to call the constructor of its base class, FooBase.
Now, what happens if I want to add another service to FooBase? I can quickly initialize the new private field from FooBase's constructor. But I still have to go around and manually update every subclass that inherits from FooBase. This can be a hassle if there are lots of inheriting classes.
Is there a shortcut, or perhaps a trick that I can use, to quickly update all t开发者_Python百科he subclasses' constructors as well?
Since I asked this question Resharper have now added support as part of the Change Signature feature.
For example, to add a parameter to a constructor in the base class, use the following method:
Right click on the constructor you want to change, select Refactor->Change Signature.
Make the changes you require and click Next. Select "Resolve with call tree" and click Next.
Your change will be made, and a window will open somewhere in Visual Studio titled "Refactoring - Change signature". A list of inheriting classes will be shown in this window.
Double click on each of the classes and choose the "Create parameter x in constructor y"
Build, then Fix compilation errors.
ReSharper has no tool for this, including AFAIK in ReSharper 6, which got launched today.
Default Value in Change Signature
The best way I know is to add new service parameter to FooBase
constructor by Change Signature (Ctrl+R,S) with a proper parameter name as default value, e.g. yetAnotherService
.
After that you have indeed errors in base
calls in all sub class constructors. But you can fix every error by only 3 key strokes:
- go to error by Alt+Shift+Page Down,
- open context menu by Alt+Enter,
- select first option (Create parameter 'yetAnotherService' in containing constructor) by Enter.
Ok you still have many key strokes. But it's the fastest way (with ReSharper 5.1.3) I know.
Parameter class by ReSharper refactoring
If you know that constructors can change through the lifetime you could create a parameter class like:
class FooInfo
{
IMyService MyService {get; set;}
IMyOtherService MyOtherService {get; set;}
}
and can pass such an object to constructor, i.e:
class FooBase
{
private FooInfo _fooInfo;
public FooBase(FooInfo fooInfo)
{
_fooInfo= fooInfo;
}
}
class FooConcrete : FooBase
{
public FooConcrete(FooInfo fooInfo)
base(fooInfo)
{
}
}
Then if you need a new parameter you just add it to FooInfo
class. Changes in subclasses are not needed.
ReSharper has a refactoring for generating such a parameter class from constructor parameters:
Place cursor on constructor name in code file and
press Ctrl+Shift+R and
select Extract Class From Parameters....
精彩评论