[C#][.Net2] Réflexions sur Reflection

[PERE]Cil revient avec sa question du jour, et bigrevindiou, elle est terrible!

Supposons une structure X (le choix ‘structure’ n’est pas inopiné, voir la suite du post), exposant les méthodes A(), B() et les propriétés internes C et D exposées par CProp et DProp. Nous avons donc:

[code]public struct X
{
public void A() { … }
public bool B() { … }

private int C;
private int D;

public CProp { get { ... } set { ... } }
public DProp { get { ... } set { ... } }

}[/code]

Cette structure doit avoir la possibilité d’être désérialisée/sérialisée en raw (tableau d’octets) pour être envoyé sur un stream réseau, c’est pourquoi nous utiliserons une structure au lieu d’une classe (qui n’est pas initialisée sur la heap, contrairement à la structure, comme expliqué par GloP dans un autre post sur ce forum).

Nous connaissons les MarshalAs, et LayoutKind. Ce sont deux “classes” qui servent a indiquer comment structurer les données internes de la structure lors de la désérialisation/sérialisation en raw, effectuées par les fonctions suivantes:

[code]// volé sur: http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/msg/aca6bf0fbe973b67
public static byte[] RawSerialize( object anything )
{
int rawsize = Marshal.SizeOf( anything );
IntPtr buffer = Marshal.AllocHGlobal( rawsize );
Marshal.StructureToPtr( anything, buffer, false );
byte[] rawdatas = new byte[ rawsize ];
Marshal.Copy( buffer, rawdatas, 0, rawsize );
Marshal.FreeHGlobal( buffer );
return rawdatas;
}

public static object RawDeserialize( byte[] rawdatas, Type anytype )
{
int rawsize = Marshal.SizeOf( anytype );
if( rawsize > rawdatas.Length )
return null;
IntPtr buffer = Marshal.AllocHGlobal( rawsize );
Marshal.Copy( rawdatas, 0, buffer, rawsize );
object retobj = Marshal.PtrToStructure( buffer, anytype );
Marshal.FreeHGlobal( buffer );
return retobj;
}[/code]

Notre structure devient donc:

[code][StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public struct X
{
public void A() { … }
public bool B() { … }

[MarshalAs( UnmanagedType.I4 )]
private int C;

[MarshalAs( UnmanagedType.I4 )]
private int D;

public CProp { get { ... } set { ... } }
public DProp { get { ... } set { ... } }

}[/code]

Comme vous pouvez le constater, C et D, propriétés internes, sont “tagguées” comme nécéssitant d’être codé sous forme d’Int comportant 4 octets.

Le but est de créer une application qui garde à tout moment les mêmes propriétés pour une structure donnée X (dont je ne connais pas par avance les propriétés). Toutefois, cette classe pourrait avoir ses données “tagguées” comme l’exemple ci dessus. Par exemple:

[code][StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public struct X
{
public void A() { … }
public bool B() { … }

[MarshalAs( UnmanagedType.I4 )]
[ReportToServer()]
private int C;

[MarshalAs( UnmanagedType.I4 )]
[ReportToServer()]
private int D;

public CProp { get { ... } set { ... } }
public DProp { get { ... } set { ... } }

}[/code]

A chaque fois que la variable C ou D serait modifiée, “quelque chose” s’occuperait de transmettre les modification de cette variable au serveur. Mes questions sont:

  • Est ce que c’est possible? (mon intuition me dit “oui”, mais je n’ai aucune idée sur comment créer ce genre de choses).

  • Comment faire pour que cela fonctionne avec n’importe quel type de variable et comment transmettre ces données au serveur (mon intuition me souffle Reflection)? Je verrais bien récupérer un “identifiant” pour la variable modifiée, stocker cet identifiant, ainsi que la variable modifiée, stocker le tout dans une structure, et l’envoyer au serveur, qui lirait l’identifiant variable, et mettrait cette variable à jour.

Ce que je ne sais pas faire:

  • trouver un identifiant de la variable (grace au namespace reflection?) et le mettre dans une structure, ainsi que la valeur de cette variable et un identifiant classe auquel cette variable appartient.
  • a partir d’une structure qui contient un identifiant pour la variable, un identifiant pour la classe et la valeur de cette variable, mettre à jour la bonne variable dans la bonne classe avec la bonne valeur.
  • faire que les deux assertions précédentes fonctionnent pour n’importe quelle classe programmée, et pas par un vieux switch dans une fonction qui renverrait un identifiant suivant la variable affectée.

Tu peux intercepter le changement d’une valeur grace a tes propriétés :
public int PropC
{
[indent]get{…}
set
{
[indent] if(value != c)
{
[indent]c = value;
//Do Something();
[/indent]
}
[/indent]
}
[/indent]

}

Oui, ca je m’en doutais bien, ce n’est pas la tellement la difficulté. Ou plutot si. Sur le client, je vais changer la propriété. Sur le serveur, qui execute le même code, comment je changes la propriété sans retransmettre à nouveau (en fait, client, serveur, c’est vague c’est du P2P).

Tiens, je viens d’avoir une illumination. Un flag sur la classe. Tellement simple.

/me retourne a son code.

Non, ca me semble etre une solution ideal pour du remoting ou indigo, et pas un systeme a la main pour refaire pareil :stuck_out_tongue:

Cherche des tutos complets sur le remoting, ou downloade indigo/winfx et cherche des tutos aussi…

J’allais le dire. Remoting ca poutre, surtout en .Net 2.0 avec l’authentification NT intégrée et le cryptage des communication.
Si t’as des soucis sur le remoting, n’hésite pas à poster, je suis actuellement sur un gros projet qui repose en partie sur du remoting.
La problématique principale (à mon sens) du remoting, est de créer une architecture où les dépendances sont réduites au minimum, et de gérer les problèmes de désynchro de version entre le client et le serveur.

Ah merde, je connaissais pas vraiment le remoting, je vais jeter un oeil dessus. Merci pour l’indication.

edit: bon après un rapide coup d’oeil ca pourrait “presque” me convenir. Le problème vient du fait que je n’ai pas un serveur centralisé, mais une architecture P2P. Ce qui veut dire que je devrais pouvoir avoir deux clients A et B connectés, B crée un objet, A le recoit, je tue B, le recrée, il se connecte à A et recoit de nouveau l’objet.

c’est tout a fait possible en remoting
et ce sera encore plus possible avec Indigo

C’est deja encore plus possible avec indigo :stuck_out_tongue: en beta tres stable je trouve pour essayer.

Ouais, mais la configuration des endpoints par fichier de conf chie grave ^^

Ca y est, c’est officiel, je comprends plus rien au thread.