2012-05-03 8 views
10

提供されたディレクトリにアセンブリを再帰的に読み込み、カスタム属性コレクションを読み込む小さなアプリケーションを作成しました。主に、DebuggableAttributeを読んでIsJITTrackingEnabledとIsJITOptimizerDisabledの設定を調べて、アセンブリがリリース用に最適化されているかどうかを判断します。現在のAppDomainにロードせずにカスタムアセンブリ属性を取得する

私の現在のコードはAssembly.LoadFromを実行してパス全体をアセンブリに渡し、ロードします。次に、デバッグ可能な属性を取得するために、アセンブリに対してGetCustomAttributesを実行します。問題は、各アセンブリが現在のappdomainにロードされることです。したがって、別のフォルダが同じアセンブリを使用する場合は、最初にロードされた参照を使用するだけです。アセンブリを読み込み、必要なプロパティを読み込んだり、アンロードしたりできます。私は新しいappdomainを作成し、アセンブリをその中にロードしてから、あとでアセンブリをアンロードしてみようとしています。

私はこれが可能でなければならないことは知っていますが、私は迷っています。どんな助けでも大歓迎です。他にも必要な情報を提供していただければ幸いです。

答えて

17

短い答えは、いいえ、あなたが求めていることをする方法がありません。

これ以上の答えは次のとおりです。「反射のみ」のロードコンテキストを使用する特殊なアセンブリロードメソッドAssembly.ReflectionOnlyLoad()があります。これにより、実行できないアセンブリをロードできますが、メタデータを読み取ることができます。

あなたのケースでは(そして、明らかに、すべてのユースケースで私は自分自身を思いつくことができます)、それは本当に役立つものではありません。この種類のアセンブリから型付き属性を取得することはできません。CustomAttributeDataのみです。そのクラスは特定の属性をフィルタリングするための良い方法を提供していません(文字列にキャストして使用することが最善でした)StartsWith("[System.Diagnostics.Debuggable");

さらに悪いことに、反射のみのロードでは依存関係はロードされませんこれは、あなたが今やっていることよりも客観的に悪いです;少なくとも今は自動的に依存関係の読み込みが行われます。

(私の以前の回答はMEF ;私は間違っていましたが、MEFにはカスタムリフレクションコードが含まれているようです。)

最終的には、それがロードされたらアセンブリをoadします。

コメントで述べたように、私は反射のみの負荷を経由して、あなたが必要な属性情報を取得することができた(とA:this MSDN article.

UPDATEで説明するように、全体のアプリケーションドメインをアンロードする必要があります通常の負荷)、型付き属性メタデータの欠如はそれを深刻な苦痛としています。

通常の組立コンテキストにロードされた場合は、情報を得ることができ、簡単に十分な必要があります:リフレクションのみのコンテキストに読み込まれた場合

var d = a.GetCustomAttributes(typeof(DebuggableAttribute), false) as DebuggableAttribute; 
var tracking = d.IsJITTrackingEnabled; 
var optimized = !d.IsJITOptimizerDisabled; 

が、あなたはいくつかの作業を行うために取得します。属性コンストラクタが取ったフォームを把握し、デフォルト値が何であるかを知り、その情報を組み合わせて各プロパティの最終値を算出しなければなりません。そこから

var d2 = a.GetCustomAttributesData() 
     .SingleOrDefault(x => x.ToString() 
           .StartsWith("[System.Diagnostics.DebuggableAttribute")); 

、あなたはコンストラクタが呼び出されたかを確認するためにConstructorArgumentsをチェックする必要があります:あなたは、このように必要な情報を取得this one二つの引数を持つ一つの引数またはthis oneで。あなたは、あなたがかかったでしょうに関心を持っている二つの特性値かを把握するために、適切なパラメータの値を使用することができます。

if (d2.ConstructorArguments.Count == 1) 
{ 
    var mode = d2.ConstructorArguments[0].Value as DebuggableAttribute.DebuggingModes; 
    // Parse the modes enumeration and figure out the values. 
} 
else 
{ 
    var tracking = (bool)d2.ConstructorArguments[0].Value; 
    var optimized = !((bool)d2.ConstructorArguments[1].Value); 
} 

最後に、あなたは、コンストラクタで設定されたものを上書きしてしまうことがありますNamedArgumentsをチェックする必要があるが、例えば使用:1つの、最終的なノートで

var arg = NamedArguments.SingleOrDefault(x => x.MemberInfo.Name.Equals("IsJITOptimizerDisabled")); 
var optimized = (arg == null || !((bool)arg.TypedValue.Value)); 

、あなたは.NET 2.0以上の下でこれを実行していて、すでに見たことがない場合は、MSDNのポイントは、このうちDebuggingModes文書で:

.NET Frameworkバージョン2.0では、JIT追跡情報が常に生成され、このフラグは、IsJITTrackingEnabledプロパティがfalseであることを除いて、Defaultと同じ効果があります。バージョン2.0では意味がありません。

+0

アンロードについての良い点! –

+0

ありがとうございます。私はそれを試みましたが、CustomAttributeDataオブジェクトを介してIsJITTrackingEnabledとIsJITOptimizerDisabledに到達することが困難でした。私はそれについて間違っていますか? – RockyMountainHigh

+0

まあ、私はあなたが望むことをすることができましたが、私はまた、 'ReflectionOnlyLoad'は基本的に役に立たないことも発見しました。それは依存関係を自動的にロードしません。*自分でロードする必要があります*。 (私は、MEFがカスタムリフレクションコンテキストを実装していることも発見しましたが、これをまったく使用していないようです。) –

0

私はAssembly.ReflectionOnlyLoadがあなたが探していると信じています。

9

Assembly.ReflectionOnlyLoadを使用する必要があります。ここで

はそれを使用する方法を示していますいくつかの MSDN Notesです:それは今までに現在のAppDomainにアセンブリをアンロードすることはできません

using System; 
using System.IO; 
using System.Reflection; 

public class ReflectionOnlyLoadTest 
{ 
    public ReflectionOnlyLoadTest(String rootAssembly) { 
     m_rootAssembly = rootAssembly; 
    } 

    public static void Main(String[] args) 
    { 
     if (args.Length != 1) { 
      Console.WriteLine("Usage: Test assemblyPath"); 
      return; 
     } 

     try { 
      ReflectionOnlyLoadTest rolt = new ReflectionOnlyLoadTest(args[0]); 
      rolt.Run(); 
     } 

     catch (Exception e) { 
      Console.WriteLine("Exception: {0}!!!", e.Message); 
     } 
    } 

    internal void Run() { 
     AppDomain curDomain = AppDomain.CurrentDomain; 
     curDomain.ReflectionOnlyPreBindAssemblyResolve += new ResolveEventHandler(MyReflectionOnlyResolveEventHandler); 
     Assembly asm = Assembly.ReflectionOnlyLoadFrom(m_rootAssembly); 

     // force loading all the dependencies 
     Type[] types = asm.GetTypes(); 

     // show reflection only assemblies in current appdomain 
     Console.WriteLine("------------- Inspection Context --------------"); 
     foreach (Assembly a in curDomain.ReflectionOnlyGetAssemblies()) 
     { 
      Console.WriteLine("Assembly Location: {0}", a.Location); 
      Console.WriteLine("Assembly Name: {0}", a.FullName); 
      Console.WriteLine(); 
     } 
    } 

    private Assembly MyReflectionOnlyResolveEventHandler(object sender, ResolveEventArgs args) { 
     AssemblyName name = new AssemblyName(args.Name); 
     String asmToCheck = Path.GetDirectoryName(m_rootAssembly) + "\\" + name.Name + ".dll"; 
     if (File.Exists(asmToCheck)) { 
      return Assembly.ReflectionOnlyLoadFrom(asmToCheck); 
     } 
     return Assembly.ReflectionOnlyLoad(args.Name); 
    } 

    private String m_rootAssembly; 
} 
4

、それはちょうど、.NETが、残念ながら動作するように設計されている方法です。 ReflectionOnlyがロードされている場合でもそうです。後者は、属性コンストラクタでコードを実行する必要があるため、通常のGetCustomAttributesの代わりにGetCustomAttributesDataメソッドを使用する必要があるだけでなく、それを行うと少しシワがあります。これは人生をより困難にする可能性があります。

代わりにCecilを使用すると、実際に正常に読み込まずにアセンブリを検査することができます。しかし、それは余分な作業の多くです。

関連する問題