web-dev-qa-db-fra.com

Comment puis-je accéder à une classe interne à partir d'un assembly externe?

Avoir un assemblage que je ne peux pas modifier (fourni par le fournisseur) et dont la méthode renvoie un objet mais qui est en réalité un type interne.

Comment puis-je accéder aux champs et/ou aux méthodes de l'objet à partir de mon assemblage?

N'oubliez pas que je ne peux pas modifier l'assembly fourni par le fournisseur.

En substance, voici ce que j'ai:

Du vendeur:

internal class InternalClass
  public string test;
end class

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

De mon assemblée en utilisant l'assembleur du vendeur.

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

Sans accès au type (et sans "InternalsVisibleTo", etc.), vous devrez utiliser la réflexion. Mais une meilleure question serait: devriez-vous accéder à ces données? Cela ne fait pas partie du contrat de type public ... il me semble qu'il est destiné à être traité comme un objet opaque (à leurs fins, pas à vous).

Vous l'avez décrit comme un champ d'instance publique. pour obtenir ceci par réflexion:

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

S'il s'agit en fait d'une propriété (pas d'un champ):

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

S'il n'est pas public, vous devrez utiliser la surcharge BindingFlags de GetField/GetProperty.

Important à part: soyez prudent avec une réflexion comme celle-ci; l'implémentation pourrait changer dans la prochaine version (casser votre code) ou être obscurcie (casser votre code) ou vous pourriez ne pas avoir assez de "confiance" (casser votre code). Êtes-vous en train de repérer le motif?

79
Marc Gravell

Je ne vois qu'un cas dans lequel vous autoriseriez une exposition de vos membres internes à une autre assemblée, à des fins de test.

Dire qu'il existe un moyen d'autoriser les assemblys "amis" à accéder aux internes:

Dans le fichier AssemblyInfo.cs du projet, vous ajoutez une ligne pour chaque assembly.

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

cette information est disponible ici.

J'espère que cela t'aides.

198
zonkflut

Je voudrais faire valoir un point - vous ne pouvez pas augmenter l’Assemblée originale - en utilisant Mono.Cecil, vous pouvez injecter [InternalsVisibleTo(...)] à l’Assemblée 3pty. Notez qu'il peut y avoir des implications juridiques - vous vous occupez de l'Assemblée vide et des implications techniques - si l'Assemblée a un nom fort, vous devez la supprimer ou la signer à nouveau avec une clé différente.

 Install-Package Mono.Cecil

Et le code comme:

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

Réflexion.

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

Utilisez le pouvoir à bon escient. N'oubliez pas de vérifier les erreurs. :)

3
Colin Burnett