Monday, October 23, 2006

Como ejecutar metodos privados de otra clase

Este articulo aplica a C# (probado en C# 2.0)

De acuerdo a la documentacion de MSDN el modificador de acceso private es el nivel de acceso mas restrictivo (acceso es limitado solo al tipo que contiene dicho miembro)

De vez en cuando quisieramos poder accesar un metodo privado en alguna clase para la cual no tenemos el codigo fuente, generalmente no deberiamos tener que hacer esto, pero pues en caso de que se ofrezca, esta es una manera de lograrlo:

primero que nada, tenemos una clase para nuestro ejemplo:

public class TestClass {
public TestClass() {
}
private void HiddenMethod() {
Console.WriteLine("secret method, should only be called from the containing class itself");
}
private string HiddenMethodWithParams(string firstName, int age) {
return string.Format("hello {0}, you are {1} years old", firstName, age);
}
}

basicamente esta clase no sirve de nada, porque no expone ningun metodo que podamos usar... a menos que tengamos acceso a los metodos privados (aun asi no sirve de nada, pero esto es solo un ejemplo =oP ):


Ahora vamos a ver como accesar los metodos privados

TestClass tc = new TestClass();
Type testClaseType = typeof(TestClass);

MethodInfo hiddenMethod =
testClaseType.GetMethod("HiddenMethod",
BindingFlags.NonPublic | BindingFlags.Instance);
hiddenMethod.Invoke(tc, null);

MethodInfo hiddenMethodWithParams =
testClaseType.GetMethod("HiddenMethodWithParams",
BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[2] { typeof(string), typeof(int) }, null);
string result = (string)hiddenMethodWithParams.Invoke(tc, new object[2] { "Eber", 25 });
Console.WriteLine("result: "+ result);

Console.Read();

vamos a ver:



  1. la primera linea simplemente crea una instancia (tc) de la clase que contiene los metodos en los que estamos interesados

  2. la segunda linea obtiene el tipo de la clase, que en este caso seria TestClass, esta variable nos servira para preguntarle informacion sobre los metodos que se encuentran en ella.

  3. luego viene lo interesante, adquirir un puntero hacia la funcion privada "HiddenMethod", los parametros BindingFlags.NonPublic y BindingFlags.Instance quieren decir: quiero un metodo no-publico (osease privado en este ejemplo), que sea un metodo proveniente de una instancia (lo opuesto de este ultimo seria estatico, ya que los metodos estaticos no se ejecutan de una instancia, sino llamandolos directamente)

  4. acto seguido, ya que tenemos un puntero a esta funcion, solo queda mandarla llamar, esto lo hacemos ejecutando el metodo Invoke, y pasando tc, la cual es la instancia en la cual se va a ejecutar el metodo (tc fue la instancia creada en la primer linea)

Basicamente eso es todo lo que hay que hacer, pero claro que una funcion que no regrese nada y que no acepte parametros pocas veces es util, asi que inclui tambien un ejemplo de llamar un metodo el cual acepta parametros y regresa algo.


Lo unico que tenemos que agregar para hacer que esta funcione, es lo siguiente:


en el paso 3, al obtener el puntero hacia el metodo que queremos ejecutar, necesitamos pasar informacion sobre los tipos de datos de los parametros de la funcion, esos datos los pasamos un arreglo; si te vas hasta arriba a ver la declaracion del metodo HiddenMethodWithParams, veras que acepta 2 parametros, un string y un int, ahora de regreso aca, eso lo especificamos asi:


new Type[2] { typeof(string), typeof(int) }


Lo cual quiere decir: 2 parametros, el primero es un string, el segundo un int


Por supuesto, podemos pasar cualquier tipo de parametro


Ahora ya tenemos el puntero al metodo que necesitamos, pero como este metodo regresa algo, pues tambien tenemos que cambiar la forma en como lo mandamos llamar:


string result = (string)hiddenMethodWithParams.Invoke(tc, new object[2] { "Eber", 25 });


aqui creamos una variable para guardar el resultado, luego mandamos llamar el metodo, haciendole una conversion al tipo de datos que sabemos que regresa (string), el parametro tc sigue igual, recuerda que ese es la instancia en la cual se esta ejecutando el metodo, por ultimo tenemos que pasar los parametros a la funcion, la manera de hacerlo es muy similar a la forma en la que le definimos el tipo de datos de los mismos


new object[2] { "Eber", 25 }


que se traduce a: 2 parametros, el primero es "Eber", el segundo es:25


Señores (y señoritas) eso todo por hoy; no abusen de esta tecnica! el codigo completo lo encuentran aqui

5 comments:

Unknown said...

como puedo obtener todos los campos privados de una clase?

Anonymous said...

como puedo llamar un metodo privado desde uno publico

BlackTigerX said...

no estoy seguro de lo que me estas preguntando, este articulo muestra como llamar un metodo privado, desde una clase externa

Francisco Cerezo said...

Gracias tio, me ha sido de mucha utilidad, eres mai jirou ;)

Sebas said...

Tiene sus años el post, pero es muy util! muchas gracias!