Pregunta C # - Cómo acceder a la clase interna desde el ensamblaje externo


Tener un ensamblaje que no puedo modificar (suministrado por el proveedor) que tiene un método que devuelve un objeto tipo, pero realmente es de tipo interno.

¿Cómo puedo acceder a los campos y / o métodos del objeto desde mi ensamblado?

Tenga en cuenta que no puedo modificar el ensamblaje suministrado por el proveedor.

En esencia, esto es lo que tengo:

Del vendedor:

internal class InternalClass
  public string test;
end class

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

Desde mi ensamblaje usando el ensamblaje del vendedor.

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

75
2018-05-28 13:27


origen


Respuestas:


Sin acceso al tipo (y sin "InternalsVisibleTo", etc.) tendría que usar el reflejo. Pero una mejor pregunta sería: debería ¿Estás accediendo a esta información? No es parte del contrato de tipo público ... me parece que está destinado a ser tratado como un objeto opaco (para sus propósitos, no para los suyos).

Lo ha descrito como un campo de instancia pública; para obtener esto a través de la reflexión:

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

Si es realmente una propiedad (no un campo):

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

Si no es público, deberá usar el BindingFlags sobrecarga de GetField/GetProperty.

Importante a un lado: ten cuidado con la reflexión como esta; la implementación podría cambiar en la próxima versión (rompiendo su código), o podría ser ofuscada (rompiendo su código), o podría no tener suficiente "confianza" (rompiendo su código). ¿Ves el patrón?


74
2018-05-28 13:32



Veo solo un caso en el que permitiría la exposición de sus miembros internos a otro conjunto y eso es para fines de prueba.

Diciendo que hay una forma de permitir que las asambleas de "amigos" accedan a las internas:

En el archivo AssemblyInfo.cs del proyecto, agrega una línea para cada ensamblaje.

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

esta información está disponible aquí.

Espero que esto ayude.


181
2018-06-12 00:52



Reflexión.

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

Usa el poder sabiamente. No te olvides de la comprobación de errores. :)


3
2018-05-28 13:34



Me gustaría argumentar un punto, que no se puede aumentar el ensamblaje original, utilizando Mono.Cecil puede inyectar [InternalsVisibleTo(...)] a la asamblea 3pty. Tenga en cuenta que puede haber implicaciones legales: está jugando con el ensamblaje 3pty y las implicaciones técnicas. Si el ensamblaje tiene un nombre fuerte, necesita quitarlo o volver a firmarlo con una clave diferente.

 Install-Package Mono.Cecil

Y el código como:

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

3
2018-06-02 13:03



Bueno, no puedes. Las clases internas no pueden ser visibles fuera de su ensamblado, por lo que no hay una forma explícita de acceder directamente a él, por supuesto, -AFAIK. La única forma es utilizar el enlace de tiempo de ejecución tardío mediante reflexión, luego puede invocar indirectamente métodos y propiedades de la clase interna.


-3
2018-05-28 13:34