IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Comment décorer une classe à l'execution ?


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Par défaut Comment décorer une classe à l'execution ?
    Je suis en train de réaliser une dll de mapping O/R, et comme je suis vraiment fainéant quand il s'agit de réécrire 12000 fois la même chose, j'aimerais que cette dll se charge de ça à ma place.

    Je pense ici précisément à l'interface INotifyPropertyChanged.

    Voici un petit exemple de ce que je souhaite obtenir...

    Soit la classe MyClass, que j'aurais écrite ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class MyClass
    {
    	private int _myInt;
     
    	public int MyInt { get { return _myInt; } set { _myInt = value; } }
     
    	public MyClass(int myInt) { _myInt = myInt; }
    }
    Et qui lors de sa compilation JIT se retrouvera ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyClass : INotifyPropertyChanged
    {
    	private int _myInt;
     
    	public int MyInt { get { return _myInt; } set { _myInt = value; OnPropertyChanged(this,new PropertyChangedEventArgs("MyInt")); } }
     
    	public MyClass(int myInt) { _myInt = myInt; }
     
    	public event PropertyChangedEventHandler PropertyChanged;
    	private void OnPropertyChanged(object sender,PropertyChangedEventArgs e){
    		if(PropertyChanged!=null)
    			PropertyChanged(sender,e);
    	}
    }
    Alors je ne sais pas si c'est possible.
    J'ai entendu parler de réécriture de méthodes, de profiling, d'AOP weaving...

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Par défaut
    Bonjour Davcha,

    il y a plusieurs moyen d'arriver à ca (donc avant-propos, oui on peut mais ce n'est pas forcement simple à mettre en place). La problematique est de generer des classes au runtime est pour ca tu peux proceder avec un weaver runtime, ou bien faire ta propre classe à la main pour "proxier" tes classes.

    La premiere solution est la plus simple, il existe pas mal de library sur le net qui te permette de faire de l'AOP, par exemple PostSharp (que j'utilise et qui est vraiment sympa) qui est en fait un weaver statique qui reecrit tes classes à la compilation (limitation normalement PostSharp doit connaitre la classe à la compilation, ce qui je pense n'est pas ton cas).

    La deuxieme solution, etant de passer par un createur de proxy dynamique, et pour ca une des libs les plus connus est DynamicProxy du projet Castle (utilisé par NHibernate par exemple). Comme beaucoup de "proxier", il procede de deux facons, soit sur base d'interface auquel cas, il reconstruit une classe implementant la dite interface qui va intercepter tes appels sur l'interface et te le notifier, soit sur base de classes concretes et dans ce cas, il va créér une nouvelle classe derivant de cette derniere en overridant les methodes (donc reservé au classe non sealed et aux methodes virtuals). Tu peux aussi l'implementer toi meme si tu preferes, ca reclame quelques connaissances en injection IL mais c'est pas reellement difficile, cette source recente sur CodeProject pourra sans doute t'aiguiller un peu.

  3. #3
    Membre Expert Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Par défaut
    Alors j'ai étudié diverses solutions, surtout du côté de l'AOP, parce que me trimballer avec des proxy ça ne me disait rien du tout.

    Du coup, j'ai opté pour PostSharp (après de nombreux tests sur les différentes solutions AOP en .NET)

    Et ça fonctionne très bien, merci

  4. #4
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Voici une source qui correspond exactement à ce que tu voulais faire. Au cas où c'est un peu différent de ce que tu as fait...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
        * using System;
        * using System.Collections.Generic;
        * using System.Linq;
        * using System.Text;
        * using System.ComponentModel;
        * using PostSharp.Laos;
        * using System.Text.RegularExpressions;
        *
        * namespace ConsoleApplication1
        * {
        * class Program
        * {
        * static void Main(string[] args)
        * {
        * Test t = new Test();
        * t.PropertyChanged += new PropertyChangedEventHandler((s, e) =>
        * {
        * Console.WriteLine(string.Format("{0} has changed", e.PropertyName));
        * });
        *
        * t.Prop1 = "a value";
        * t.Prop2 = "a value";
        * t.Prop3 = "a value";
        * }
        * }
        *
        * [NotifyPropertyChanged]
        * public class Test : INotifyPropertyChanged
        * {
        * public string Prop1 { get; set; }
        *
        * public string Prop2;
        *
        * private string _Prop3;
        *
        * public string Prop3
        * {
        * get { return _Prop3; }
        * set { _Prop3 = value; }
        * }
        *
        * #region INotifyPropertyChanged Members
        *
        * public event PropertyChangedEventHandler PropertyChanged;
        *
        * #endregion
        * }
        *
        * [Serializable]
        * public class NotifyPropertyChanged : OnFieldAccessAspect
        * {
        * public override void OnSetValue(FieldAccessEventArgs eventArgs)
        * {
        * base.OnSetValue(eventArgs);
        *
        * var owner = eventArgs.Instance;
        *
        * string propertyName = string.Empty;
        * string fieldName = eventArgs.FieldInfo.Name;
        * Regex reg = new Regex(@"(<)(\w*?)(>k__BackingField)");
        * Match match = reg.Match(fieldName);
        * if (match.Success)
        * propertyName = match.Groups[2].Value;
        * else if(fieldName.StartsWith("~"))
        * propertyName = fieldName.Replace("~", string.Empty);
        * else if(fieldName.StartsWith("_"))
        * propertyName = fieldName.Replace("_", string.Empty);
        *
        * var e = new PropertyChangedEventArgs(propertyName);
        *
        * FireEvent(owner, "PropertyChanged", e);
        * }
        *
        * //http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=776014&SiteID=1
        * public void FireEvent(object owner, string name, EventArgs e)
        * {
        * MulticastDelegate eventDelagate =
        * (MulticastDelegate)owner.GetType().GetField(name,
        * System.Reflection.BindingFlags.Instance |
        * System.Reflection.BindingFlags.NonPublic).GetValue(owner);
        *
        * if (eventDelagate != null)
        * {
        * Delegate[] delegates = eventDelagate.GetInvocationList();
        *
        * foreach (Delegate dlg in delegates)
        * dlg.Method.Invoke(dlg.Target, new object[] { owner, e });
        * }
        * }
        * }
        * }

  5. #5
    Membre Expert Avatar de davcha
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 258
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 258
    Par défaut
    Oui, enfin, depuis j'en suis plus à INotifyPropertyChanged, j'ai ajouté d'autres éléments à cette interface qui maintenant s'appelle Chipie.Mapping.IPersistable.

  6. #6
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Et qui fais quoi en plus ? (Sans indiscrétion) Le mapping O/R m'intéresse énormément.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 04/09/2007, 16h00
  2. Réponses: 2
    Dernier message: 15/06/2006, 12h37
  3. Comment renvoyer une classe perso ?
    Par Cyrilange dans le forum Services Web
    Réponses: 5
    Dernier message: 03/05/2006, 16h54
  4. Réponses: 6
    Dernier message: 01/05/2006, 19h05
  5. Réponses: 1
    Dernier message: 07/09/2005, 22h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo