Comment passer une méthode en paramètre?

Comment passer une méthode en paramètre? - C#/.NET managed - Programmation

Marsh Posté le 01-03-2008 à 12:59:38    

Mes yeux sont maintenant rouge de sang, c'est maintenant 3h49 du matin (Vancouver) et j'ai plus le courage à chercher...  
 
Je souhaite définir un callback comme ceci:
 
 

Code :
  1. class Form1
  2. {
  3.     int compteur;
  4.     pubic Form1()
  5.     {
  6.         compteur = 0;
  7.         Prout prout = new Prout();
  8.         prout.SetCallback(this.IncCompteur)
  9.     }
  10.     public IncCompteur()
  11.     {
  12.         compteur++;
  13.     }
  14. }
  15. class Prout
  16. {
  17.     private delegate void callback();
  18.     public Prout()
  19.     {
  20.     }
  21.     public SetCallback(object tocall)
  22.     {
  23.         callback = new callback(tocall);
  24.     }
  25.     private UnThread()
  26.     {
  27.         while(1)
  28.         {
  29.             // Des choses...
  30.             // Encode des choses...
  31.             callback();
  32.             // Et puis encore des choses...
  33.         }
  34.     }
  35. }


 
Le problème c'est que cette partie là génère une erreur:
 

Code :
  1. public SetCallback(object tocall)
  2.     {
  3.         callback = new callback(tocall);
  4.     }


 
Cette partie là aussi d'ailleurs:
 

Code :
  1. prout.SetCallback(this.IncCompteur)


 
Pouvez-vous m'aider un peu?  
 
Merci d'avance

Reply

Marsh Posté le 01-03-2008 à 12:59:38   

Reply

Marsh Posté le 01-03-2008 à 17:55:22    

pour moi tu dois faire appel à un delegué. Renseigne toi la dessus.

Reply

Marsh Posté le 01-03-2008 à 21:34:49    

Oui c'est bien ce que je pensais c'est d'ailleurs ce que j'utilise dans mon exemple :)

Reply

Marsh Posté le 01-03-2008 à 22:18:55    

Bon j'avance gentillement mais c'est pas encore ca...  
 

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. namespace ConsoleApplication1
  7. {
  8.     //---------------------- MAIN ---------------------//
  9.     class Program
  10.     {
  11.         // Main program
  12.         static void Main(string[] args)
  13.         {
  14.             // Set delegate
  15.             ActionHandler actionHandler = new ActionHandler(Action);
  16.             // Start service and set callback
  17.             Service service = new Service();
  18.             service.SetCallback(actionHandler);
  19.             service.Run();
  20.             // Do nothing
  21.             Console.ReadLine();
  22.         }
  23.         // Method called by the service...
  24.         delegate void ActionHandler();
  25.         static void Action()
  26.         {
  27.             Console.WriteLine("I was called!" );
  28.         }
  29.     }
  30.     //--------------------- SERVICE -------------------//
  31.     class Service
  32.     {
  33.         delegate void RemoteEvent();
  34.         RemoteEvent remoteEvent;
  35.         public Service()
  36.         {
  37.             remoteEvent = null;
  38.         }
  39.         public void Run()
  40.         {
  41.             Thread backgroundTask = new Thread(new ThreadStart(BackgroundTask));
  42.             backgroundTask.Start();
  43.         }
  44.         public void SetCallback(object remoteHandler)
  45.         {
  46.             RemoteEvent remoteEvent = (RemoteEvent)remoteHandler;
  47.         }
  48.         private void OnRemoteEvent()
  49.         {
  50.             if (remoteEvent != null)
  51.                 remoteEvent();
  52.         }
  53.         public void BackgroundTask()
  54.         {
  55.             for (int i = 0; i < 10; i++)
  56.             {
  57.                 Console.WriteLine("Hard Job, huh!" );
  58.                 System.Threading.Thread.Sleep(2000);
  59.                 OnRemoteEvent();
  60.             }
  61.         }
  62.     }
  63. }

Reply

Marsh Posté le 01-03-2008 à 22:25:32    

Bon finalement j'ai trouvé une solution mais Ô que c'est laid.... Il suffisait de déclarer le délégué en dehors de toute classe.  
 
Avez-vous une autre alternative plus "propre"
 
 

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. namespace ConsoleApplication1
  7. {
  8.     delegate void RemoteEvent();
  9.     //---------------------- MAIN ---------------------//
  10.     class Program
  11.     {
  12.         // Main program
  13.         static void Main(string[] args)
  14.         {
  15.             // Set delegate
  16.             RemoteEvent actionHandler = new RemoteEvent(Action);
  17.             // Start service and set callback
  18.             Service service = new Service();
  19.             service.SetCallback(actionHandler);
  20.             service.Run();
  21.             // Do nothing
  22.             Console.ReadLine();
  23.         }
  24.         // Method called by the service...
  25.         //delegate void ActionHandler();
  26.         static void Action()
  27.         {
  28.             Console.WriteLine("I was called!" );
  29.         }
  30.     }
  31.     //--------------------- SERVICE -------------------//
  32.     class Service
  33.     {       
  34.         RemoteEvent remoteEvent;
  35.         public Service()
  36.         {
  37.             remoteEvent = null;
  38.         }
  39.         public void Run()
  40.         {
  41.             Thread backgroundTask = new Thread(new ThreadStart(BackgroundTask));
  42.             backgroundTask.Start();
  43.         }
  44.         public void SetCallback(RemoteEvent remoteHandler)
  45.         {
  46.             remoteEvent = remoteHandler;
  47.         }
  48.         private void OnRemoteEvent()
  49.         {
  50.             if (remoteEvent != null)
  51.                 remoteEvent();
  52.         }
  53.         public void BackgroundTask()
  54.         {
  55.             for (int i = 0; i < 10; i++)
  56.             {
  57.                 Console.WriteLine("Hard Job, huh!" );
  58.                 System.Threading.Thread.Sleep(2000);
  59.                 OnRemoteEvent();
  60.             }
  61.         }
  62.     }
  63. }

Reply

Marsh Posté le 01-03-2008 à 23:23:39    

Bon je continue sur la lancée...  
J'ai trouvé beaucoup plus propre avec l'utilisation des évènements. Il suffit de définir la méthode appelée lorsque l'évènement "Modified" est déclanché.
 

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. namespace ConsoleApplication1
  7. {
  8.     delegate void RemoteEvent();
  9.     //---------------------- MAIN ---------------------//
  10.     class Program
  11.     {
  12.         // Main program
  13.         static void Main(string[] args)
  14.         {
  15.             // Start service and set event
  16.             Service service   = new Service();
  17.             service.Modified += new EventHandler(Action);
  18.             service.Run();
  19.             // Do nothing
  20.             Console.ReadLine();
  21.         }
  22.         // Method called by the service...
  23.         static void Action(object sender, EventArgs e)
  24.         {
  25.             Console.WriteLine("I was called!" );
  26.         }
  27.     }
  28.     //--------------------- SERVICE -------------------//
  29.     class Service
  30.     {
  31.         public event EventHandler Modified;
  32.         public Service()
  33.         {
  34.         }
  35.         public void Run()
  36.         {
  37.             Thread backgroundTask = new Thread(new ThreadStart(BackgroundTask));
  38.             backgroundTask.Start();
  39.         }
  40.         private void OnModified(EventArgs e)
  41.         {
  42.             if (Modified != null)
  43.                 Modified(this, e);
  44.         }
  45.         public void BackgroundTask()
  46.         {
  47.             for (int i = 0; i < 10; i++)
  48.             {
  49.                 // Hard Job
  50.                 Console.WriteLine("Hard Job, huh!" );
  51.                 System.Threading.Thread.Sleep(2000);
  52.                 // Fire the event
  53.                 OnModified(EventArgs.Empty);
  54.             }
  55.         }
  56.     }
  57. }

Reply

Marsh Posté le 02-03-2008 à 01:28:54    

Bon cette fois-ci on s'écarte beaucoup de l'origine mais le principe reste le même.
 
Un service et un client. Le client appel le service et défini des "évènements" suivant:
 
- Quand le processus à progressé
- Quand le processus est terminé
 
J'ai rajouté un GUI pour que ce soit plus ceux qui veulent tester. Il suffit de créer un nouveau projet sous Visual Studio C#, de supprimer le fichier Form1.Designer.cs, faire clic droit sur Form1.cs et sélectionner View Code. Ensuite il suffit juste de coller le code suivant en remplacant tout.
 
J'ai atteint mon but et je suis content...  
 

Code :
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. namespace WindowsFormsApplication1
  10. {
  11.     /// <summary>
  12.     /// Main Form
  13.     /// </summary>
  14.     public class Form1 : Form
  15.     {
  16.         #region Non Interesting...
  17.         private System.ComponentModel.IContainer components = null;
  18.         protected override void Dispose(bool disposing)
  19.         {
  20.             if (disposing && (components != null))
  21.             {
  22.                 components.Dispose();
  23.             }
  24.             base.Dispose(disposing);
  25.         }
  26.         #region Windows Form Designer generated code
  27.         private void InitializeComponent()
  28.         {
  29.             this.progressBar1 = new System.Windows.Forms.ProgressBar();
  30.             this.label2 = new System.Windows.Forms.Label();
  31.             this.textBox1 = new System.Windows.Forms.TextBox();
  32.             this.SuspendLayout();
  33.             //  
  34.             // progressBar1
  35.             //  
  36.             this.progressBar1.Location = new System.Drawing.Point(15, 25);
  37.             this.progressBar1.Name = "progressBar1";
  38.             this.progressBar1.Size = new System.Drawing.Size(267, 19);
  39.             this.progressBar1.TabIndex = 2;
  40.             //  
  41.             // label2
  42.             //  
  43.             this.label2.AutoSize = true;
  44.             this.label2.Location = new System.Drawing.Point(12, 9);
  45.             this.label2.Name = "label2";
  46.             this.label2.Size = new System.Drawing.Size(64, 13);
  47.             this.label2.TabIndex = 5;
  48.             this.label2.Text = "Current Job:";
  49.             //  
  50.             // textBox1
  51.             //  
  52.             this.textBox1.Location = new System.Drawing.Point(15, 50);
  53.             this.textBox1.Multiline = true;
  54.             this.textBox1.Name = "textBox1";
  55.             this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
  56.             this.textBox1.Size = new System.Drawing.Size(267, 167);
  57.             this.textBox1.TabIndex = 6;
  58.             //  
  59.             // Form1
  60.             //  
  61.             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
  62.             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  63.             this.ClientSize = new System.Drawing.Size(292, 224);
  64.             this.Controls.Add(this.textBox1);
  65.             this.Controls.Add(this.label2);
  66.             this.Controls.Add(this.progressBar1);
  67.             this.Name = "Form1";
  68.             this.Text = "Test";
  69.             this.ResumeLayout(false);
  70.             this.PerformLayout();
  71.         }
  72.         #endregion
  73.         private System.Windows.Forms.ProgressBar progressBar1;
  74.         private System.Windows.Forms.Label label2;
  75.         private System.Windows.Forms.TextBox textBox1;
  76.         #endregion
  77.         Service service = new Service();
  78.         public Form1()
  79.         {
  80.             InitializeComponent();
  81.             // Start a background job
  82.             service.ProgressChanged = new ProgressChangedEventHandler(ProgressChanged);
  83.             service.CompletedEvent = new RunWorkerCompletedEventHandler(ProcessCompleted);
  84.             service.Run();
  85.         }
  86.         public void ProgressChanged(object sender, ProgressChangedEventArgs e)
  87.         {
  88.             progressBar1.Value = e.ProgressPercentage;
  89.             textBox1.AppendText("Current Value: " + service.Value.ToString() + Environment.NewLine);
  90.         }
  91.         private void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
  92.         {
  93.             MessageBox.Show("Job Done!" );
  94.         }
  95.     }
  96.     /// <summary>
  97.     /// Service
  98.     /// </summary>
  99.     public class Service
  100.     {
  101.         private BackgroundWorker job;
  102.         public ProgressChangedEventHandler ProgressChanged;
  103.         public RunWorkerCompletedEventHandler CompletedEvent;
  104.         private delegate void Change(string str);
  105.         public int Value;
  106.         public Service()
  107.         {
  108.             job = new BackgroundWorker();
  109.             job.DoWork += new DoWorkEventHandler(backgroundJob_DoWork);         
  110.         }
  111.         public void Run()
  112.         {
  113.             job.RunWorkerAsync();
  114.             if (ProgressChanged != null)
  115.             {
  116.                 job.ProgressChanged += ProgressChanged;
  117.                 job.WorkerReportsProgress = true;
  118.             }
  119.             if (CompletedEvent != null)
  120.             {
  121.                 job.RunWorkerCompleted += CompletedEvent;
  122.             }
  123.            
  124.         }   
  125.         private void backgroundJob_DoWork(object sender, DoWorkEventArgs e)
  126.         {
  127.             for (int i = 0; i <= 100; i++)
  128.             {
  129.                 // Hard and long job
  130.                 System.Threading.Thread.Sleep(10);
  131.                 // Return values during process
  132.                 if (i % 10 == 0)
  133.                 {
  134.                     Value = i;
  135.                     (sender as BackgroundWorker).ReportProgress(i);
  136.                 }               
  137.             }
  138.         }     
  139.     }
  140. }

Reply

Marsh Posté le 05-03-2008 à 02:02:45    

Je suis un peu à la bourre, mais en gros...
 
Si j'ai bien pigé, t'as une application, et tu veux qu'un traîtement asynchrone tourne, et te prévienne de son avancement, c'est ça ?
 
Si oui, plutôt que de jouer avec des events, joue plutôt avec des Threads, c'est là pour ça.
 
Et qui plus est, les BackgroundWorker, qui sont d'une simplicité extrême à utiliser.
 
Exemple complet avec 3 boutons :
bouton1 = start
bouton2 = stop
bouton3 = pause/resume
Une progressbar qui indique où en est le worker
Un label qui indique l'état du worker
Une textbox qui indique jusqu'à combien compter (afin de provoquer une erreur si désiré)
 

Code :
  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows.Forms;
  4.  
  5. namespace SampleBackgroundWorker
  6. {
  7.    public partial class Form1 : Form
  8.    {
  9.        int COUNTER_DONE;
  10.        BackgroundWorker bw = new BackgroundWorker();
  11.        byte WorkingCounter = 0;
  12.  
  13.        public Form1()
  14.        {
  15.            InitializeComponent();
  16.  
  17.            COUNTER_DONE = int.Parse(textBox1.Text);
  18.  
  19.            progressBar1.Minimum = 0;
  20.            progressBar1.Maximum = 100;
  21.  
  22.            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
  23.            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
  24.            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
  25.            bw.WorkerReportsProgress = true;
  26.            bw.WorkerSupportsCancellation = true;
  27.  
  28.            button3.Enabled = false;
  29.            button2.Enabled = false;
  30.        }
  31.  
  32.        private void button1_Click(object sender, EventArgs e)
  33.        {
  34.            button1.Enabled = false;
  35.            button2.Enabled = true;
  36.            button3.Enabled = true;
  37.            button3.Text = "Pause";
  38.            bw.RunWorkerAsync((object)false);
  39.        }
  40.  
  41.        private void button2_Click(object sender, EventArgs e)
  42.        {
  43.            if (bw.IsBusy)
  44.            {
  45.                button2.Enabled = false;
  46.                bw.CancelAsync();
  47.            }
  48.        }
  49.  
  50.        private void button3_Click(object sender, EventArgs e)
  51.        {
  52.            if (bw.IsBusy)
  53.            {
  54.                button2.Enabled = false;
  55.                button3.Text = "Resume";
  56.                bw.CancelAsync();
  57.            }
  58.            else
  59.            {
  60.                button1.Enabled = false;
  61.                button3.Text = "Pause";
  62.                bw.RunWorkerAsync((object)true);
  63.            }
  64.        }
  65.  
  66.        private void bw_DoWork(object sender, DoWorkEventArgs e)
  67.        {
  68.            bool resume = (bool)e.Argument;
  69.  
  70.            if (!resume)
  71.            {
  72.                WorkingCounter = 0;
  73.            }
  74.  
  75.            while (WorkingCounter < COUNTER_DONE)
  76.            {
  77.                Random rnd = new Random();
  78.                if (WorkingCounter > (WorkingCounter += 10))
  79.                {
  80.                    throw new Exception(string.Format("Dépassement du type du compteur : {0} pour {1}.", (byte)(WorkingCounter - 10) + 10, byte.MaxValue));
  81.                }
  82.  
  83.                int Percent = (int)WorkingCounter * 100 / COUNTER_DONE;
  84.  
  85.                bw.ReportProgress(Percent, (object)false);
  86.                System.Threading.Thread.Sleep(250);
  87.  
  88.                if (bw.CancellationPending)
  89.                {
  90.                    e.Cancel = true;
  91.                    bw.ReportProgress(Percent, (object)true);
  92.                    System.Threading.Thread.Sleep(500);
  93.                    break;
  94.                }
  95.            }
  96.  
  97.            e.Result = (object)WorkingCounter;
  98.        }
  99.  
  100.        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
  101.        {
  102.            progressBar1.Value = e.ProgressPercentage;
  103.            if ((bool)e.UserState)
  104.            {
  105.                label1.Text = "Le worker est en cours d'arrêt...";
  106.            }
  107.            else
  108.            {
  109.                label1.Text = string.Format("Le worker fonctionne normalement... ({0}%)", e.ProgressPercentage);
  110.            }
  111.        }
  112.  
  113.        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  114.        {
  115.            if (e.Error != null)
  116.            {
  117.                label1.Text = string.Format("Le worker s'est terminé avec une erreur :\n{0}.", e.Error.Message);
  118.            }
  119.            else
  120.            {
  121.                if (e.Cancelled)
  122.                {
  123.                    label1.Text = "Le worker s'est arrêté à la demande de l'utilisateur.";
  124.                    button3.Enabled = false;
  125.                }
  126.                else
  127.                {
  128.                    label1.Text = string.Format("Le worker a fini de compter jusqu'à {0}.", e.Result);
  129.                    button3.Enabled = true;
  130.                }
  131.            }
  132.            button1.Enabled = true;
  133.            button2.Enabled = false;
  134.        }
  135.  
  136.        private void textBox1_TextChanged(object sender, EventArgs e)
  137.        {
  138.            COUNTER_DONE = int.Parse(textBox1.Text);
  139.        }
  140.    }
  141. }


 
-- Merde, j'avais pas fait gaffe que c'est ce à quoi t'es arrivé au final :D
En tout cas, c'est clairement la façon la plus élégante de faire ce genre de choses.
Tu peux aussi gérer des thread à la main, mais c'est infiniment plus complexe pour des possibilités dont on n'a pas forcément besoin.
 
Attention, le test sur "e.Error" dans le completed est très important : si le worker raise une exception, il va la trapper tout seul comme un grand, et la stocker à dedans.
Toute tentative d'accès à "e.Result" avec "e.Error != null" provoque une "InvalidOperationException" !


Message édité par MagicBuzz le 05-03-2008 à 02:34:24
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed