web-dev-qa-db-ja.com

外部アセンブリから内部クラスにアクセスするにはどうすればよいですか?

objectタイプを返すメソッドを持っているが、実際には内部タイプ。

アセンブリからオブジェクトのフィールドやメソッドにアクセスするにはどうすればよいですか?

ベンダー提供のアセンブリを変更できないことに注意してください。

本質的に、ここに私が持っているものがあります:

ベンダーから:

internal class InternalClass
  public string test;
end class

public class Vendor
  private InternalClass _internal;
  public object Tag {get{return _internal;}}
end class

ベンダーアセンブリを使用してアセンブリから。

public class MyClass
{
  public void AccessTest()
  {
    Vendor vendor = new Vendor();
    object value = vendor.Tag;
    // Here I want to access InternalClass.test
  }
}
89
Stécy

型へのアクセスなしで(および "InternalsVisibleTo"などがない)、リフレクションを使用する必要があります。しかし、より良い質問は次のとおりです:shouldこのデータにアクセスしていますか?それはパブリックタイプのコントラクトの一部ではありません...それは不透明なオブジェクトとして扱われることを意図しているように聞こえます(あなたの目的ではなく、その目的のため)。

パブリックインスタンスフィールドとして説明しました。リフレクションを介してこれを取得するには:

object obj = ...
string value = (string)obj.GetType().GetField("test").GetValue(obj);

実際にプロパティ(フィールドではない)の場合:

string value = (string)obj.GetType().GetProperty("test").GetValue(obj,null);

非公開の場合は、BindingFlags/GetFieldGetPropertyオーバーロードを使用する必要があります。

重要なことは別として:このようなリフレクションには注意してください。実装が次のバージョンで変更される(コードが破損する)か、難読化される(コードが破損する)か、十分な「信頼」がない(コードが破損する)可能性があります。パターンを見つけていますか?

79
Marc Gravell

私は、内部メンバーが別のアセンブリにさらされることを許可し、それがテスト目的である場合を1つだけ見ています。

「フレンド」アセンブリが内部にアクセスできるようにする方法があると言って:

プロジェクトのAssemblyInfo.csファイルで、アセンブリごとに行を追加します。

[Assembly: InternalsVisibleTo("name of Assembly here")]

この情報は利用可能です こちら

お役に立てれば。

198
zonkflut

Mono.Cecilを使用して[InternalsVisibleTo(...)]を3ptyアセンブリに注入できるという点を、元のアセンブリを拡張することはできないということを主張したいと思います。法的意味があるかもしれないことに注意してください-3ptyアセンブリと技術的な意味をいじっています-アセンブリに厳密な名前がある場合、それを取り除くか、別のキーで再署名する必要があります。

 Install-Package Mono.Cecil

そして、次のようなコード:

static readonly string[] s_toInject = {
  // alternatively "MyAssembly, PublicKey=0024000004800000... etc."
  "MyAssembly"
};

static void Main(string[] args) {
  const string THIRD_PARTY_Assembly_PATH = @"c:\folder\ThirdPartyAssembly.dll";

   var parameters = new ReaderParameters();
   var asm = ModuleDefinition.ReadModule(INPUT_PATH, parameters);
   foreach (var toInject in s_toInject) {
     var ca = new CustomAttribute(
       asm.Import(typeof(InternalsVisibleToAttribute).GetConstructor(new[] {
                      typeof(string)})));
     ca.ConstructorArguments.Add(new CustomAttributeArgument(asm.TypeSystem.String, toInject));
     asm.Assembly.CustomAttributes.Add(ca);
   }
   asm.Write(@"c:\folder-modified\ThirdPartyAssembly.dll");
   // note if the Assembly is strongly-signed you need to resign it like
   // asm.Write(@"c:\folder-modified\ThirdPartyAssembly.dll", new WriterParameters {
   //   StrongNameKeyPair = new StrongNameKeyPair(File.ReadAllBytes(@"c:\MyKey.snk"))
   // });
}
5
Ondrej Svejdar

反射。

using System.Reflection;

Vendor vendor = new Vendor();
object tag = vendor.Tag;

Type tagt = tag.GetType();
FieldInfo field = tagt.GetField("test");

string value = field.GetValue(tag);

力を賢く使ってください。エラーチェックを忘れないでください。 :)

3
Colin Burnett