後編 Visual Studio 2017のリファクタリング機能:特集:Visual Studioで始めるリファクタリング(3/4 ページ)
変数レベル/メソッドレベル/型レベルでのリファクタリングを支援するために、Visual Studio 2017が提供している機能を取り上げる。
メソッドレベルのリファクタリング
メソッドに関しては、前編で紹介した「名前の変更」の他に、メソッドの抽出やシグネチャの変更などがサポートされている。
『メソッドの抽出』(Extract Method)
別のメソッドとして切り出したい範囲を選択して、リファクタリングサポート機能の[メソッドの抽出]を選ぶ(次のコードはこの機能を使って、リファクタリング前のコードの中から強調書体で示した部分を別メソッドに抽出したものだ)。
// リファクタリング前
static void SampleMethod(Point p1, Point p2)
{
double dX = p2.X - p1.X;
double dY = p2.Y - p1.Y;
double distance = Math.Sqrt(dX * dX + dY * dY);
double slope = dY / dX;
Console.WriteLine($"2点間の距離は{distance},傾きは{slope}");
}
// ↓
// リファクタリング後
static void SampleMethod(Point p1, Point p2)
{
double distance, slope;
CalcDistanceAndSlope(p1, p2, out distance, out slope);
Console.WriteLine($"2点間の距離は{distance},傾きは{slope}");
}
private static void CalcDistanceAndSlope(Point p1, Point p2, out double distance, out double slope)
{
double dX = p2.X - p1.X;
double dY = p2.Y - p1.Y;
distance = Math.Sqrt(dX * dX + dY * dY);
slope = dY / dX;
}
// 参考:タプルを返すようにリファクタリング(手動)
static void SampleMethod(Point p1, Point p2)
{
(var distance, var slope) = CalcDistanceAndSlope(p1, p2);
Console.WriteLine($"2点間の距離は{distance},傾きは{slope}");
}
private static (double distance, double slope)
CalcDistanceAndSlope(Point p1, Point p2)
{
double dX = p2.X - p1.X;
double dY = p2.Y - p1.Y;
return (Math.Sqrt(dX * dX + dY * dY), dY / dX);
}
太字にした4行を範囲指定してメソッドの抽出を行った。範囲指定した中で宣言している変数2つ(distanceとslope)を後の文で使用していることに注意。
抽出したメソッドは2つの値(distanceとslope)を返さねばならないので、out引数を使ったメソッドになった(.NET Framework 4.7を使っているのだが、残念ながら本稿執筆時点では参考に示したようなタプルを返すメソッドにはしてくれなかった)。返すべき値が1つだけの場合は、もちろん返値として返すメソッドが生成される。
『パラメータの削除』(Remove Parameter)
メソッド内部で使っていないパラメーター(引数)を削除する。VS 2017では、併せてパラメーターの順序の入れ替えもできる。
この機能の使い方は他と少し異なる。メソッド名(定義部分でも呼び出し部分でも)を指定して[署名の変更]を選ぶと、次の画像のようなダイアログが出てくるので、そこで不要になったパラメーターを削除したり、順序を入れ替えたりする(「署名」とは「signature」つまりメソッドのシグネチャのことだ)。
上のダイアログで[OK]ボタンをクリックすれば、メソッドを呼び出している部分もそれに合わせて変更される(次のコードはこの機能を使って、リファクタリング前のコードにあるパラメーター「scale」を削除し、パラメーター「p1」「p2」の順序を入れ替えたものだ)。
// リファクタリング前
private static (double distance, double slope)
CalcDistanceAndSlope4(Point p1, Point p2, double scale)
{
double dX = p2.X - p1.X;
double dY = p2.Y - p1.Y;
//return (Math.Sqrt(dX * dX + dY * dY) * scale, dY / dX);
// 以前はパラメーター「scale」を使っていたが、今は使っていない
return (Math.Sqrt(dX * dX + dY * dY), dY / dX);
}
static void SampleMethod4(Point p1, Point p2)
{
(var distance, var slope) = CalcDistanceAndSlope4(p1, p2, 1.0);
Console.WriteLine($"2点間の距離は{distance},傾きは{slope}");
}
// ↓
// リファクタリング後
private static (double distance, double slope)
CalcDistanceAndSlope4(Point p2, Point p1)
{
double dX = p2.X - p1.X;
double dY = p2.Y - p1.Y;
//return (Math.Sqrt(dX * dX + dY * dY) * scale, dY / dX);
// 以前はパラメーター「scale」を使っていたが、今は使っていない
return (Math.Sqrt(dX * dX + dY * dY), dY / dX);
}
static void SampleMethod4(Point p1, Point p2)
{
(var distance, var slope) = CalcDistanceAndSlope4(p2, p1);
Console.WriteLine($"2点間の距離は{distance},傾きは{slope}");
}
「CalcDistanceAndSlope4」メソッドに対して「署名の変更」を適用し、パラメーター「scale」は削除し、パラメーター「p1」「p2」の順序は入れ替えた。メソッドを呼び出している部分もきちんと書き換えられていることに注目。他のソリューションからは使われていないメソッドならば、このように簡単にパラメーターの削除や入れ替えができる。
ただし、メソッド内で使っているパラメーターでも削除できてしまう(その結果はコンパイルエラーになる)ので、注意が必要だ。
ラムダ式のボディーを通常の書法に
これはC#ならではの機能だ。逆向きの機能、つまり、通常の書き方をしたボディーをラムダ式に書き換える機能は、残念なことにまだ装備されていないようだ。
ラムダ式(を使って定義しているメソッド)の中にカーソルを置き(範囲指定しなくてもよい)、リファクタリングサポート機能の[メソッドにブロック本体を使用する]を選ぶ(次のコードはこの機能を使ってラムダ式を使って定義したメソッドを、ブロック形式の定義に置き換えたものだ)。
// リファクタリング前
static long Square(int n) => n * n;
// ↓
// リファクタリング後
static long Square(int n)
{
return n * n;
}
最後に型レベルのリファクタリングを行うために、VS 2017が提供している機能を見てみよう。
Copyright© Digital Advantage Corp. All Rights Reserved.