usar - ¿ en c# qué es método?
C#- Cómo acceder a la clase interna desde el ensamblaje externo (5)
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.
Tener un ensamblaje que no puedo modificar (suministrado por el proveedor) que tiene un método que devuelve un tipo de objeto pero que 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
}
}
Me gustaría argumentar un punto, que no se puede aumentar el ensamblaje original, utilizando Mono.Cecil puede inyectar [InternalsVisibleTo(...)]
al ensamblaje 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"))
// });
}
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. :)
Sin acceso al tipo (y sin "InternalsVisibleTo", etc.) tendría que usar el reflejo. Pero una mejor pregunta sería: ¿ debería acceder 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 la sobrecarga BindingFlags
de GetField
/ GetProperty
.
Importante aparte : tenga 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?
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 here.
Espero que esto ayude.