2009-05-28 5 views
72

を内部クラスにアクセスするオブジェクト型を返すメソッドを持っていますが、内部のタイプで本当にです。C#の - どのように私は(ベンダー提供)を変更することはできませんアセンブリを有する外部のアセンブリから

どのように私は私のアセンブリからフィールドおよび/またはオブジェクトのメソッドにアクセスすることができますか?

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

は本質的には、ここで私が持っているものです:ベンダーから

:私のアセンブリから

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 
    } 
} 

答えて

70

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

あなたはパブリックインスタンスフィールドとしてそれを説明してきました。それは実際にはプロパティ(ないフィールド)である場合

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

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

それは非公開である場合、あなたはGetFieldBindingFlagsオーバーロードを使用する必要がありますリフレクションを経由して、これを取得します/ GetProperty

脇重要:このような反射には注意してください。次のバージョンで実装が変更される可能性があります(コードを壊す)、または難読化する(コードを壊す)、十分な "信頼"がない(コードを破る)可能性があります。あなたはパターンを点いていますか?

+1

WOOO。2分!ぎりぎりでした!まあ、マーク(常に)と述べた。 :D – Galilyou

+0

素晴らしい!それは動作します。私はこの方法で内部にアクセスできないと思っていました...ありがとうございます –

+0

Marc私はプライベートフィールド/プロパティにアクセスすることは可能ですが、正しいタイプを使用してGetValueによって返されたオブジェクトをキャストする方法はありますか? – codingadventures

-3

まあ、できません。内部クラスはアセンブリの外部では表示できないため、直接アクセスする明示的な方法はありません。 唯一の方法は、リフレクションを使用して実行時レイトバインディングを使用し、内部クラスからメソッドとプロパティを間接的に呼び出すことです。

+0

zonkflutの解決策は過去に私のために働いていた – phlip

+0

それは呼び出されたアセンブリを編集することに依存します – phlip

+4

反射で何かを呼び出すことができます –

3

リフレクション。

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); 

電源を賢明に使用してください。エラーチェックを忘れないでください。 :)

171

内部メンバーに別のアセンブリへの公開を許可するのは、テスト目的の場合のみです。

あなたは各アセンブリのための行を追加します。プロジェクトのAssemblyInfo.csファイルで:内部への「フレンド」のアセンブリへのアクセスを許可する方法があることを言っ

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

この情報はhere.

は、この情報がお役に立てば幸い可能です。

+1

ちょうど今日、私はscreencstを驚かせて、アセンブリ)はそれにアクセスできますが、どのようにそれを行うのか分かりませんでした。 ありがとうございます! –

+3

これは私にとって有益な情報だったので投票してください...これは質問の答えにはなりませんが:-D – yeyeyerman

+4

質問には、特にパートナーのアセンブリを修正できないという質問があります。投票ダウン。 – danielpops

3

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

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")) 
    // }); 
} 
+0

私にとっては、修正することはできません。それは、それがナゲットから来ることを意味し、修正を加えてローカルナゲットを作成して管理する必要はありません。また、一部の人にとっては、強い名前の紛失が問題になります。しかし、これは興味深い点です。 – binki