64 votes

C# : Fonction dans la fonction possible ?

Est-il possible de déclarer une méthode à l'intérieur d'une autre méthode en C# ?

Par exemple, comme ça :

void OuterMethod()
{
    int anything = 1;
    InnerMethod();     // call function
    void InnerMethod()
    {
        int PlitschPlatsch = 2;
    }
}

0 votes

Pourquoi voulez-vous faire cela ? Quel problème essayez-vous de résoudre ? Quelle situation essayez-vous de modéliser ?

1 votes

@Cody Gray J'ai une méthode avec beaucoup de code, que je veux structurer pour une meilleure lecture et compréhension. Comme cette partie du code n'est pas nécessaire aux autres méthodes, j'ai pensé à diviser le code à l'intérieur de la méthode.

5 votes

Oui, et c'est exactement pourquoi j'ai demandé. Beaucoup de personnes utiles parlent de lambdas et de Func mais ce n'est pas vraiment ce que vous voulez ici. Si vous pensez avoir besoin de refactorer du code à partir d'une méthode existante, créez simplement une nouvelle méthode dans votre fichier .cs et assurez-vous qu'il est marqué private . Si vous n'avez pas besoin de l'appeler depuis un autre endroit, alors ne le faites pas. Il n'y a aucune raison de compliquer inutilement les choses.

61voto

JaredPar Points 333733

Mise à jour : Fonctions locales ont été ajoutés dans la version 7 du C#.

void OuterMethod()
{
    int foo = 1;
    InnerMethod();
    void InnerMethod()
    {
        int bar = 2;
        foo += bar
    }
}

Dans la version précédente de C#, vous deviez utiliser une action comme celle-ci :

void OuterMethod()
{
    int anything = 1;
    Action InnedMethod = () =>
    {
        int PlitschPlatsch = 2;
    };
    InnedMethod();
}

0 votes

Comment passer des paramètres ?

0 votes

Erreur : il faut un point-virgule après : foo += bar

41voto

jeroenh Points 12777

MISE À JOUR : C#7 a ajouté des fonctions locales ( https://docs.microsoft.com/en-us/dotnet/articles/csharp/csharp-7#local-functions )

void OuterMethod()
{
    int foo = 1;

    InnerMethod();

    void InnerMethod()
    {
        int bar = 2;
        foo += bar
    }

}

Dans les versions de C# antérieures à C#7, vous pouvez déclarer un objet Func o Action et obtenir quelque chose de similaire :

void OuterMethod()
{
    int foo = 1;
    Action InnerMethod = () => 
    {
        int bar = 2;
        foo += bar;
    } ;

    InnerMethod();
}

0 votes

@cheeso : Parce que c'est une solution facile que le langage supporte si bien.

0 votes

Cela ne fonctionnera pas en C#. "Impossible d'assigner une méthode anonyme à une variable locale implicitement typée".

0 votes

@nitro cela fonctionne très bien. L'exemple n'utilise pas de variable locale implicitement typée (c'est à dire que la fonction var mot-clé). Il contenait cependant quelques fautes de frappe, que j'ai corrigées.

16voto

Cheeso Points 87022

Oui, il y a des moyens. Avec C# 3.0, vous disposez de la Func<T> qui fait cela.

Par exemple, j'ai écrit ceci hier :

  var image = Image.FromFile(_file);
  int height = image.Height;
  int width = image.Width;
  double tan = height*1.00/width;
  double angle = (180.0 * Math.Atan(tan) / Math.PI);
  var bitmap = new System.Drawing.Bitmap(image, width, height);
  var g = System.Drawing.Graphics.FromImage(bitmap);
  int fontsize = 26; // starting guess
  Font font = null;
  System.Drawing.SizeF size;

  Func<SizeF,double> angledWidth = new Func<SizeF,double>( (x) =>
      {
          double z = x.Height * Math.Sin(angle) +
          x.Width * Math.Cos(angle);
          return z;
      });

  // enlarge for width
  do
  {
      fontsize+=2;
      if (font != null) font.Dispose();
      font = new Font("Arial", fontsize, System.Drawing.FontStyle.Bold);
      size = g.MeasureString(_text, font);
  }
  while (angledWidth(size)/0.85 < width);

Le but était d'ajouter un filigrane à une image existante. Je voulais que la taille du texte du filigrane représente environ 85 % de la largeur de l'image. Mais je voulais incliner le texte du filigrane pour qu'il soit écrit sur un angle. Cela a révélé la nécessité d'effectuer quelques calculs trigonométriques basés sur les angles, et je voulais une petite fonction pour effectuer ce travail. Le site Func est parfait pour cela.

Le code ci-dessus définit un Func (une fonction) qui accepte un SizeF et renvoie un double pour la largeur réelle du texte lorsqu'il est dessiné selon l'angle donné. Ce site Func est une variable dans une fonction, et la variable elle-même contient une (référence à une) fonction. Je peux alors invoquer cette fonction "privée" dans la portée où je l'ai définie. La fonction a accès aux autres variables qui sont définies avant elle, dans son champ d'exécution. Ainsi, le angle est accessible dans le cadre de la angledWidth() fonction.


Si vous voulez une logique invocable qui renvoie void vous pouvez utiliser Action<T> de la même manière. .NET définit des génériques Func qui acceptent N arguments, ce qui permet de les rendre assez compliqués. Un Func est comme une fonction VB ou une méthode C# qui renvoie des données non vides ; une Action est comme un Sub VB ou une méthode C# qui renvoie des données vides.

9voto

dss539 Points 2821

Cinq ans ont passé depuis que cette question a été posée et maintenant C# 7 arrive.

Il est prévu d'inclure des fonctions locales, et est apparemment déjà mis en œuvre.

Fonctions locales (Proposition : #259) [actuellement dans la branche future].

https://github.com/dotnet/roslyn/issues/259

1 votes

Je tiens à préciser qu'à mon avis, avant d'utiliser cette fonction, vous devriez réfléchir sérieusement à ce que vous faites. Il est possible que votre méthode devienne trop volumineuse pour être facilement lisible.

3voto

zneak Points 45458

El delegate Le mot-clé fait exactement cela.

void OuterMethod()
{
    var InnerMethod = delegate()
    {
        int PlitschPlatsch = 2;
    };

    int anything = 1;
    InnerMethod();
}

N'oubliez pas que, conformément à la définition du champ d'application, la PlitschPlatsch ne sera pas accessible en dehors de InnerMethod.

1 votes

Probablement parce qu'il n'y a qu'une seule bonne façon de le faire. De plus, ce n'est pas exactement la même chose.

4 votes

Cela ne fonctionnera pas en C#. "Impossible d'assigner une méthode anonyme à une variable locale implicitement typée".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X