![](http://nesteruk.org/pix/0/0944bf8b-45ef-4449-a91b-1ba9fcb07454.jpg)
using Biztalk
を
using Biztalk
して作成
using Biztalk
ときにリンクを自動的に追加する機会が与えられるため、これは必要ありません。 スタジオはこれを行う方法を知らないので、私は彼女を助けなければなりませんでした。
アイデア自体はシンプルで、2つの部分で構成されています。
- すべての重要なアセンブリを見つけて、すべての名前空間にインデックスを付ける必要があります。
- を
using
てカーソルを合わせると、可能なすべてのアセンブリを検索してメニューを表示する必要があります。
索引付け
名前空間とアセンブリファイルパスのベースは数秒で完了します。 唯一のトリックは、
Assembly.ReflectionOnlyLoad()
などの依存関係の代わりにCecilを使用することです。これは、依存関係などをロードしようとします。 すべての型をすばやく見つけ、それらの名前空間を
HashSet
書き留め、データベースにすべて入れます。 どうやって? これについては今から話します。
まず、参照の追加が使用するファイルへのパスは、レジストリとPublicAssembliesフォルダーの少なくとも2つの場所にあります。 レジストリにリストされているフォルダーを見つけるために、次のコードを作成しました。
public static IEnumerable< string > GetAssemblyFolders()<br/>
{<br/>
string [] valueNames = new [] { string .Empty, "All Assemblies In" };<br/>
string [] keyNames = new []<br/>
{<br/>
@"SOFTWARE\Microsoft\.NETFramework\AssemblyFolders" ,<br/>
@"SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders" <br/>
};<br/>
var result = new HashSet< string >();<br/>
foreach ( var keyName in keyNames)<br/>
{<br/>
using ( var key = Registry.LocalMachine.OpenSubKey(keyName))<br/>
{<br/>
if (key != null )<br/>
foreach ( string subkeyName in key.GetSubKeyNames())<br/>
{<br/>
using ( var subkey = key.OpenSubKey(subkeyName))<br/>
{<br/>
if (subkey != null )<br/>
{<br/>
foreach ( string valueName in valueNames)<br/>
{<br/>
string value = (subkey.GetValue(valueName) as string ?? string .Empty).Trim();<br/>
if (! string .IsNullOrEmpty( value ))<br/>
result.Add( value );<br/>
}<br/>
}<br/>
}<br/>
}<br/>
}<br/>
}<br/>
return result;<br/>
}<br/>
最初は、私のためにほとんど機能しませんでした。 32ビットシステムと64ビットシステムのキーは異なります。 ここでも、64ビットシステムへの移行に伴い、より良いコードを記述し始めたことに気付きました。
PublicAssembliesフォルダーを見つけるには、まずVisual Studioがインストールされている場所を見つける必要があります。
public static string GetVS9InstallDirectory()<br/>
{<br/>
var keyNames = new string []<br/>
{<br/>
@"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0\Setup\VS" ,<br/>
@"SOFTWARE\Microsoft\VisualStudio\9.0\Setup\VS" <br/>
};<br/>
foreach ( var keyName in keyNames)<br/>
{<br/>
using ( var key = Registry.LocalMachine.OpenSubKey(keyName))<br/>
{<br/>
if (key != null )<br/>
return key.GetValue( "ProductDir" ).ToString();<br/>
}<br/>
}<br/>
return null ;<br/>
}<br/>
フォルダーのリストがあると、それぞれのすべてのDLLファイルを検索し、それらにインデックスを付けることができます。 [参照の追加]ダイアログに常に表示されるフォルダーに加えて、独自のフォルダーを追加できます。これは便利です。
using ( var dc = new StatsDataContext())<br/>
{<br/>
var dirs = new HashSet< string >();<br/>
dirs.Add( @"C:\Program Files (x86)\JetBrains\ReSharper\v4.5\Bin" );<br/>
foreach ( var dir in GetAssemblyFolders()) dirs.Add(dir);<br/>
dirs.Add(Path.Combine(GetVS9InstallDirectory(), @"Common7\IDE\PublicAssemblies" ));<br/>
foreach ( string dir in dirs.Where(Directory.Exists))<br/>
{<br/>
string [] files = Directory.GetFiles(dir, "*.dll" );<br/>
var entries = new HashSet<Namespace>();<br/>
foreach ( string file in files)<br/>
{<br/>
var ns = AddNamespacesFromFile(file);<br/>
foreach ( var n in ns)<br/>
entries.Add(n);<br/>
}<br/>
dc.Namespaces.InsertAllOnSubmit(entries);<br/>
}<br/>
dc.SubmitChanges();<br/>
}<br/>
AddNamespacesFromFile()
メソッドを使用して追加を行います。これは、私が書いたようにMono.Cecilを使用します。
private static IEnumerable<Namespace> AddNamespacesFromFile( string file)<br/>
{<br/>
HashSet<Namespace> result = new HashSet<Namespace>();<br/>
try <br/>
{<br/>
var ad = AssemblyFactory.GetAssembly(file);<br/>
foreach (ModuleDefinition m in ad.Modules)<br/>
{<br/>
foreach (TypeDefinition type in m.Types)<br/>
{<br/>
if (type.IsPublic && ! string .IsNullOrEmpty(type.Namespace))<br/>
{<br/>
result.Add( new Namespace<br/>
{<br/>
AssemblyName = ad.Name.Name,<br/>
AssemblyVersion = ad.Name.Version.ToString(),<br/>
NamespaceName = type.Namespace,<br/>
PhysicalPath = file<br/>
});<br/>
}<br/>
}<br/>
}<br/>
}<br/>
catch <br/>
{<br/>
// it's okay, probably a non-.Net DLL
}<br/>
return result;<br/>
}<br/>
ベースの充填で、それだけです。 さらに、結果を使用できますが、データを更新して新しいパスを追加できるバックグラウンドユーティリティも作成しました。
使用する
より良いオプションがないため、ReSharperのコンテキストアクションとしてリンクの追加を実装しました。 アイデアは簡単です-ユーザーは、
using Biztalk;
して行の
Biztalk
という単語に
Biztalk
を合わせ
using Biztalk;
プロジェクトにリンクが自動的に追加される要素を選択すると、魔法のメニューが表示されます。
CA自体は、有用なクラス
CSharpContextActionBase
から継承します
CSharpContextActionBase
内部では、「適用可能性」のチェックは別として、スマートなことは何も起こりません。 データベースは
SELECT * from Namespaces where NamespaceName LIKE '%BizTalk%'
単純な
SELECT * from Namespaces where NamespaceName LIKE '%BizTalk%'
を使用して検索されます。 数千個の要素を持つベース(試してみると、おそらく1万個)には、このアプローチが適切です。
protected override bool IsAvailableInternal()<br/>
{<br/>
items = EmptyArray<IBulbItem>.Instance;<br/>
var element = GetSelectedElement<IElement>( false );<br/>
if (element == null )<br/>
return false ;<br/>
var parent = element.ToTreeNode().Parent;<br/>
if (parent == null || parent.GetType().Name != "ReferenceName" || parent.Parent == null <br/>
|| string .IsNullOrEmpty(parent.Parent.GetText()))<br/>
return false ;<br/>
string s = parent.Parent.GetText();<br/>
if ( string .IsNullOrEmpty(s))<br/>
return false ;<br/>
var bulbItems = new HashSet<RefBulbItem>();<br/>
using ( var conn = new SqlConnection(<br/>
"Data Source=(local);Initial Catalog=Stats;Integrated Security=True" ))<br/>
{<br/>
conn.Open();<br/>
var cmd = new SqlCommand(<br/>
"select * from Namespaces where NamespaceName like '%" + s + "%'" , conn);<br/>
using ( var r = cmd.ExecuteReader())<br/>
{<br/>
int count = 0;<br/>
while (r.Read())<br/>
{<br/>
bulbItems.Add( new RefBulbItem(<br/>
provider,<br/>
r.GetString(2).Trim(),<br/>
r.GetString(3).Trim(),<br/>
r.GetString(4).Trim()));<br/>
count++;<br/>
}<br/>
if (count > 0)<br/>
{<br/>
items = System.Linq.Enumerable.ToArray(<br/>
System.Linq.Enumerable.ThenBy(<br/>
System.Linq.Enumerable.OrderBy(<br/>
bulbItems,<br/>
i => i.AssemblyName),<br/>
i => i.AssemblyVersion));<br/>
return true ;<br/>
}<br/>
}<br/>
}<br/>
return false ;<br/>
}<br/>
興味深いことはすべて
BulbItem
ahで発生します。つまり、コンテキストメニューの呼び出し中に表示される黄色の電球です。 電球自体は特定のPOCOであり、適切なタイミングで特定のアセンブリへのリンクを追加できます。
protected override void ExecuteBeforeTransaction(ISolution solution,<br/>
JetBrains.TextControl.ITextControl textControl, IProgressIndicator progress)<br/>
{<br/>
var project = provider.Project;<br/>
if (project == null ) return ;<br/>
var fileSystemPath = FileSystemPath.TryParse(path);<br/>
if (fileSystemPath == null ) return ;<br/>
var assemblyFile = provider.Solution.AddAssembly(fileSystemPath);<br/>
if (assemblyFile == null ) return ;<br/>
var cookie = project.GetSolution().EnsureProjectWritable(project, out project, SimpleTaskExecutor.Instance);<br/>
QuickFixUtil.ExecuteUnderModification(textControl,<br/>
() => project.AddModuleReference(assemblyFile.Assembly),<br/>
cookie);<br/>
}<br/>
上記のコードは、JetBrainsチームのメンバー( プレーナー -ありがとう!) 私自身は正しい道を見つける忍耐を持っていませんでした。
おわりに
この機能を実装することでどれだけの時間を節約したかはわかりませんが、「座って参照を追加する」というスタイルの頭痛は確実に少なくなりました。 また、お気に入りのアセンブリセット(DI、モック、検証、ユーティリティなど)を使用してプロジェクトをコンパイルするのがはるかに簡単になりました。 ■