Comment appeler une méthode privée en C# ?
Récemment, j’ai du rechercher une solution afin de pouvoir récupérer une valeur depuis une propriété privée.
Cette valeur était nécessaire pour décoder un flux HTTP et malheureusement, elle était encapsulée (et cachée) par le framework .NET.
Heureusement, en .NET, il est très facile d’accéder à un membre privé d’une autre classe.
Bien sûr, ce type de mécanisme casse l’encapsulation et est contraire aux principes objet. Néanmoins, parfois cela devient nécessaire.
Mon besoin a été le suivant : je souhaitais faire un appel à une méthode privée dans une autre classe. Par défaut, le compilateur l’interdit, c’est la raison d’être du mot clé private.
Par les mécanismes de réflexion proposés par .NET, il est possible d’accéder à quasiment n’importe quel membre de n’importe quelle classe.
L’opération est réalisée de la manière suivante:
- Il faut tout d’abord récupérer l’instance de la classe que l’on veut « espionner ».
- Ensuite, on récupère son type avec la méthode GetType().
- A partir de là, on récupère soit un membre directement (si l’on connait le nom), soit par énumération des membres (GetFields, GetMethods). Dans l’exemple, je connais le nom.
- On effectue ensuite une invocation pour récupérer la valeur du membre (propriété ou méthode).
Voici un exemple qui montre simplement comment cela fonctionne:
using System;
// Nécessaire pour accéder aux classes de la réflexion.
using System.Reflection;
namespace TestReflection
{
class MyPrivateClass
{
private int GetPrivateValue()
{
return 5;
}
public int GetPublicValue()
{
return 10;
}
}
static class Program
{
///
/// Point d’entrée de notre exemple
///
[MTAThread]
static void Main()
{
MyPrivateClass myClass = new MyPrivateClass();
int value1 = myClass.GetPublicValue();
// Ceci est impossible en temps normal
// value = myClass.GetPrivateValue();
// Récupérer le type:
Type classType = myClass.GetType();
// Récupérer les informations sur la méthode
// (flags: important pour les membres privés)
MethodInfo mi = classType.GetMethod("GetPrivateValue",
BindingFlags.Instance | BindingFlags.NonPublic);
// Faire une invocation:
object result = mi.Invoke(myClass, null);
int value2 = (int)result;
Console.Write("value1={0}, value2={1}", value1, value2);
}
}
}
Voilà donc une méthode simple pour accéder à un membre privé. Attention toutefois de n’utiliser ceci qu’avec précaution car tous les membres privés peuvent changer d’une version du framework à l’autre (ce qui peut donc vous obliger de revoir « l’astuce » à chaque nouvelle version).