using System;
using System.Threading;

namespace ex_XXX_005_passage_de_paramètre
{
    class Program
    {
        static void AfficheCarréDeObject(object nombre)
        {
            float nombreFloat = (float)nombre;
            Console.WriteLine("{0} ({1})", nombreFloat * nombreFloat, Thread.CurrentThread.Name);
        }

        static void AfficheCarréDeFloat(float nombre)
        {
            Console.WriteLine("{0} ({1})", nombre * nombre, Thread.CurrentThread.Name);
        }

        static void Main(string[] args)
        {
            //passage de paramètre dans un thread
            Thread thread = new Thread(AfficheCarréDeObject) { Name = "thread1" };
            thread.Start(3.0f);
            //équivalent à (c'est ce qui est reconstruit par le compilateur) :
            ParameterizedThreadStart parameterizedThreadStart = new ParameterizedThreadStart(AfficheCarréDeObject);
            thread = new Thread(parameterizedThreadStart) { Name = "thread2" };
            thread.Start(3.0f);
            //inconvénients : 
            //- on ne peut passer qu'un seul paramètre
            //- ce paramètre doit obligatoirement être de type object, ce qui implique un cast

            //Depuis C#3, on peut le faire aussi avec une expression lambda,
            //ce qui permet de :
            //- passer un paramètre typé (pas forcément object)
            thread = new Thread(() => AfficheCarréDeFloat(3.0f)) { Name = "thread3" };
            thread.Start();
            //- passer plusieurs paramètres
            thread = new Thread(() => AfficheMultiplicationDeFloat(2.0f, 3.0f)) { Name = "thread4" };
            thread.Start();

            thread.Join();
            Console.WriteLine();

            //ATTENTION toutefois aux expressions lambda :
            //(lancez ce programme plusieurs fois pour bien identifier le problème)
            //la sortie n'est pas sûre, car la variable i (son espace mémoire en particulier) 
            //est utilisée par les 10 threads mais on ne sait pas exactement quand.
            //i peut avoir changé (i++) avant que le thread n'ait eu le temps d'appeler la méthode
            for (int i = 0; i < 10; i++)
            {
                thread = new Thread(() => AfficheCarréDeFloat(i)) { Name = "thread5" };
                thread.Start();
            }
            thread.Join();
            Console.WriteLine();

            //la solution consiste à utiliser une variable temporaire qui ne sera pas partagée et ne sera pas modifiée
            for (int i = 0; i < 10; i++)
            {
                int temp = i;
                thread = new Thread(() => AfficheCarréDeFloat(temp)) { Name = "thread6" };
                thread.Start();
            }
        }

        static void AfficheMultiplicationDeFloat(float nombre1, float nombre2)
        {
            Console.WriteLine("{0} ({1})", nombre1 * nombre2, Thread.CurrentThread.Name);
        }
    }
}
