リファクタリングの作成経験

私は最近、異なる名前空間からの名前の衝突の問題に遭遇しました。 C#では、名前空間の同義語を導入できます。 完全修飾クラス名を使用する代わりに、この名前空間へのアクセスに使用できるプレフィックスを入力します。



Visual StudioとReSharperを使用して、すでに記述されているクラスに同義語を入力する簡単な方法を見つけませんでした。 これに関連して、この問題を解決するReSharperへの追加を実装することにしました。 この記事では、私が直面しなければならない落とし穴についてお話したいと思います。一見したところ、このような単純なリファクタリングを実現しています。 (ソースコードと記事の最後の実装)



だから。 このようなことをするためのコードを取得したかったのです。

using b.b2; class Example { MyTest test; }
      
      





 using x = b.b2; class Example { x.MyTest test; }
      
      







私の嬉しいことに、ReSharper-aオブジェクトモデルにより、各タイプのFQN(完全修飾名)、つまり この例では、MyTestクラスがネームスペースb.b2およびそのFQN b.b2.MyTestにあることを確認できます。



アルゴリズムの最初の定式化は以下のようになります

b.b2名前空間にエイリアスxを導入したい場合、この使用が適用されるコードの部分で使用されるすべての型に対して:型の使用がb.b2スペースにあり、コードの記述がFQNを使用しない場合、追加する必要がありますプレフィックスx。



問題があります-拡張メソッドを忘れていました。 拡張メソッドは、名前空間がファイルに明示的にインポートされた場合にのみ呼び出すことができます。 直接インポートを同義語に置き換えると、コンパイラは呼び出す必要のあるメソッドを見つけることができません。 この問題は簡単に解決されます-b.b2名前空間にあるクラスの拡張メソッド。 それらが存在する静的クラスのメンバーとして呼び出す必要があります。

だった なります する必要がある
 using b.b2; class Example { MyTest test; Example() { test.Ext(); } }
      
      





 using x = b.b2; class Example { x.MyTest test; Example() { test.Ext();// Ext   } }
      
      





 using x = b.b2; class Example { x.MyTest test; Example() { x.Extension.Ext(test); } }
      
      







次は、テストファイルのリファクタリングを開始しようとして、私が偶然見つけたレーキです。 たとえば、FQNが使用されているかどうかを単に比較することはできません。

だった なります する必要がある
 using r = b.b2; using b.b2; class Example { r.MyTest test; }
      
      





 using r = b.b2; using x = b.b2; class Example { xrMyTest test; // r  }
      
      





 using r = b.b2; using b.b2; class Example { r.MyTest test; }
      
      







そのようなエラーが発生するのは、 MyTestのFQNはb.b2.MyTestです。 この情報を知っているリファクタリングは、接尾辞を追加します。 このエラーは、プレフィックスを追加する代わりに、x。[ShortTypeName]の型を使用して完全な置換を使用する場合に修正できます。



名前の競合

それとは別に、xの値が定義済みのものと競合する場合に問題があります

 using b.b2; class x { class MyTest{} } class Example { MyTest test; }
      
      





 using x = b.b2; class x { class MyTest{} } class Example { x.MyTest test; // Error namespace contains a definition conflicting with alias 'x' }
      
      







適切なリファクタリングにより、そのようなエラーの結果を確認する必要があります。 実装では、この問題を無視し、開発者の肩に移しました。 さらに、競合が発生した場合、コンパイラはこれを確実に報告します。



クエリ式

もう1つの問題が残っています。 ユーザーがSystem.Linq名前空間(など)の同義語を入力する場合はどうなりますか。 拡張メソッドを使用する場合、アルゴリズムは素晴らしく対処します。 しかし、query-expressionが使用される場合、何も良い結果は得られません

だった なります
 using System.Linq; ... var query = from c in svcContext.ContactSet join a in svcContext.AccountSet on c.ContactId equals a.PrimaryContactId.Id where a.Name.Contains("Contoso") where c.LastName.Contains("Smith") select new { account_name = a.Name, contact_name = c.LastName };
      
      





 using aaa = System.Linq; // Error Could not find an implementation of the query pattern for // source type 'string[]'. // 'Select' not found. Are you missing a reference to 'System.Core.dll' // or a using directive for 'System.Linq'? var query = // from c in svcContext.ContactSet join a in svcContext.AccountSet on c.ContactId equals a.PrimaryContactId.Id where a.Name.Contains("Contoso") where c.LastName.Contains("Smith") select new { account_name = a.Name, contact_name = c.LastName };
      
      







適切なリファクタリングは、クエリ式を静的メソッドの呼び出しのチェーンに展開し(実際にはコンパイラが実行します)、次のようなものを取得する必要があります。

 var query = aaa.Enumerable.Select( aaa.Enumerable.Where( aaa.Enumerable.Where( aaa.Enumerable.Join( svcContext.ContactSet, svcContext.AccountSet, c => c.ContactId, a => a.PrimaryContactId.Id, (c, a) => new { c, a }), @t => @taName.Contains("Contoso")), @t => @tcLastName.Contains("Smith")), @t => new { account_name = @taName, contact_name = @tcLastName });
      
      





リファクタリングがコードを非常に酷くm笑している場合、開発者は満足しているとは思いません。 したがって、私の実装では、これらの名前空間の同義語を許可しません。



実装に関するいくつかの言葉

ネットワークには、リシャーパー用のプラグインの作成方法に関するかなりの情報があります。 主な情報源は逆コンパイラです。 SDKは少し役立ちます。拡張機能の作成例がいくつかあります(ただし、リファクタリング用の例は1つだけです)。



ソースコードはGitHubで入手できますが、ReSharperの内部キッチンについて学ぶためにそれらを使用しないことを強くお勧めします。



結果は私に合った。 誰かが役に立つといいな。

resharper-plugins.jetbrains.com/packages/IntroduceNsAlias

github.com/ulex/IntroduceNsAlias



ReSharperのプラグイン作成者向けの追加情報:

•逆コンパイラ

confluence.jetbrains.com/display/NETCOM/ReSharper+Plugin+Development

tv.jetbrains.net/videocontent/getting - started - with - resharper - sdk



All Articles