// ========================================================================
//
// Copyright (C) 2016-2017 MARC CHEVALDONNE
//                         marc.chevaldonne.free.fr
//
// Module        : Program.cs
// Author        : Marc Chevaldonné
// Creation date : 2016-09-23
// Mise à jour   : 2017-09-28
//
// ========================================================================

using System;
using static System.Console;

namespace ex_010_001_methodParametersAndModifiers
{
    class ExFunct
    {
        //passage d'arguments par valeur
        public int Somme(int a, int b)
        {
            int result = a + b;
            //celui qui appelle cette méthode ne pourra pas voir ces changements
            //car a et b sont ici des copies locales des paramètres qu'il a passés
            a++;
            b++;
            return result;
        }

        //passage d'argument par référence (notez le mot-clé ref)
        public int SommeRef(ref int a, ref int b)
        {
            int result = a + b;
            //celui qui appelle cette méthode verra les deux paramètres qu'il a passés
            //modifiés par celle-ci, car ils sont passés par référence
            a++;
            b++;
            return result;
        }

        //passage de tableaux en argument (pas besoin de préciser ref, le tableau en est une)
        public int SommeTab(int[] tab)
        {
            int result = 0;
            for (int i = 0; i < tab.Length; i++)
            {
                //celui qui appelle cette méthode verra les valeurs du tableau passé en paramètre
                //modifiées par la méthode, car un tableau est toujours passé par référence
                //(un tableau EST un type REFERENCE)
                result += tab[i];
                tab[i]++;
            }
            return result;
        }

        //passage d'argument out : indique que la variable est initialisée par la fonction appelée (notez le mot-clé out)
        public void SommeOut(int a, int b, out int result)
        {
            //celui qui appelle cette méthode peut donner result sans l'initialiser
            //le mot-clé out garantit que ce paramètre sera initialisé dans la méthode
            result = a + b;
        }

        //passage d'arguments en nombre indéterminé, en dernier paramètre de la méthode uniquement
        public int SommeParams(params int[] ints)
        {
            //l'utilisateur de la méthode n'a pas besoin de préciser params
            //en revanche, il peut passer autant d'arguments de type int qu'il le souhaite.
            //À l'intérieur de la méthode, ces arguments sont traités comme un tableau d'entiers,
            //mais tous les éléments de ce tableau sont copiés par valeur.
            int result = 0;
            for (int i = 0; i < ints.Length; i++)
            {
                result += ints[i];
                ints[i]++;
            }
            return result;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OutputEncoding = System.Text.Encoding.UTF8;

            ExFunct f = new ExFunct();
            int a = 2;
            int b = 3;
            WriteLine("f.Somme(a, b)");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine($"résultat : {f.Somme(a, b)}"); //passage d'arguments par valeur
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine();

            WriteLine("f.SommeRef(ref a, ref b)");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine($"résultat : {f.SommeRef(ref a, ref b)}");//passage d'argument par référence (notez le mot clé ref) --> a est modifié par la fonction
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine();

            WriteLine("tableaux");
            int[] t = { 1, 2, 3 };
            Write("tableau t (avant) : ");
            foreach (int i in t) Write($"{i} ");
            WriteLine();
            f.SommeTab(t); //passage de tableau en argument (pas besoin de ref, car c'est est une).
            WriteLine("f.SommeTab(t);");
            Write("tableau t (après) : ");
            foreach (int i in t) Write($"{i} ");
            WriteLine();
            WriteLine();

            int c;
            WriteLine("f.SommeOut(a, b, out c);");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine("c est non assigné");
            f.SommeOut(a, b, out c);
            WriteLine($"résultat : {c}"); //passage d'argument out. c n'est pas initialisé, et on utilise le mot clé out
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine($"c (après) = {c}");
            WriteLine();

            //Dans l'exemple ci-dessus de l'utilisation des paramètres out, il est nécessaire de déclarer c avant son utilisation :
            //int c;
            //f.SommeOut(a, b, out c);
            //Depuis C# 7.0, l'utilisation a été simplifiée : vous pouvez maintenant déclarer la variable lors de son utilisation :
            //f.SommeOut(a, b, out int c2);
            //La portée de la variable est alors le bloc contenant l'instruction prenant le paramètre out en paramètre.

            WriteLine("f.SommeOut(a, b, out int c2);");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine("c2 est non assigné et déclaré lors de l'appel de la méthode SommeOut");
            f.SommeOut(a, b, out int c2);
            WriteLine($"résultat : {c2}"); //passage d'argument out. c2 n'est pas initialisé, et on utilise le mot clé out
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine($"c2 (après) = {c2}");
            WriteLine();

            //Il est également possible d'utiliser var, tant qu'il n'y a pas de conflit (surcharge de méthodes), ce qui rend l'utilisation encore plus simple
            WriteLine("f.SommeOut(a, b, out var c3);");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine("c3 est non assigné et déclaré lors de l'appel de la méthode SommeOut");
            f.SommeOut(a, b, out var c3);
            WriteLine($"résultat : {c3}"); //passage d'argument out. c3 n'est pas initialisé, et on utilise le mot clé out
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine($"c3 (après) = {c3}");
            WriteLine();

            //Enfin, il est également possible de préciser qu'on veut ignorer une variable out avec _ (discard variables)
            WriteLine("f.SommeOut(a, b, out _);");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine("on ne souhaite pas récupérer le paramètre en out");
            f.SommeOut(a, b, out _);
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine();

            WriteLine("f.SommeParams(a, b, c)");
            WriteLine($"a (avant) = {a}");
            WriteLine($"b (avant) = {b}");
            WriteLine($"c (avant) = {c}");
            //passage d'arguments en nombre indéterminé
            WriteLine($"résultat : {f.SommeParams(a, b, c)}");
            WriteLine($"a (après) = {a}");
            WriteLine($"b (après) = {b}");
            WriteLine($"c (après) = {c}");
            WriteLine();
        }
    }
}
